[ofa-general] [PATCH] opensm: multicast multiplexing many mgid to mlid

Slava Strebkov slavas at Voltaire.COM
Thu Jun 18 05:52:10 PDT 2009


>From cc95291fc8c9a5e2f9bb1367ffbf5930509a30c1 Mon Sep 17 00:00:00 2001
From: Slava Strebkov <slavas at voltaire.com>
Date: Thu, 18 Jun 2009 15:02:34 +0300
Subject: [PATCH] multicast multiplexing many mgid to mlid

This patch implements multicast multiplexing as proposed in the
thread entitled "IPv6 and IPoIB scalability issue".
It includes both IPv6 SNM groups collapsing and IPv4 special groups
(All hosts, routers, gateways) and muxing of many IPoIB MGIDs to single MLID
according to mask of MGID least significant bits.
Addition patch will allow mask configuration from opensm configuration file.

Signed-off-by: Slava Strebkov <slavas at voltaire.com>
---
 opensm/include/opensm/osm_mgrp_holder.h |  428 +++++++++++++++++++++++++++++++
 opensm/include/opensm/osm_multicast.h   |   15 +-
 opensm/include/opensm/osm_sm.h          |    8 +-
 opensm/include/opensm/osm_subnet.h      |    6 +-
 opensm/opensm/Makefile.am               |    1 +
 opensm/opensm/osm_drop_mgr.c            |   11 +-
 opensm/opensm/osm_mcast_mgr.c           |  211 +++++++++-------
 opensm/opensm/osm_mgrp_holder.c         |  315 +++++++++++++++++++++++
 opensm/opensm/osm_multicast.c           |   57 +++--
 opensm/opensm/osm_qos_policy.c          |   42 ++--
 opensm/opensm/osm_sa.c                  |   38 ++-
 opensm/opensm/osm_sa_mcmember_record.c  |  144 ++++++-----
 opensm/opensm/osm_sa_path_record.c      |   18 +-
 opensm/opensm/osm_sm.c                  |   73 +++++-
 opensm/opensm/osm_subnet.c              |   11 +-
 15 files changed, 1114 insertions(+), 264 deletions(-)
 create mode 100644 opensm/include/opensm/osm_mgrp_holder.h
 create mode 100644 opensm/opensm/osm_mgrp_holder.c

diff --git a/opensm/include/opensm/osm_mgrp_holder.h b/opensm/include/opensm/osm_mgrp_holder.h
new file mode 100644
index 0000000..05b1c14
--- /dev/null
+++ b/opensm/include/opensm/osm_mgrp_holder.h
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#ifndef _OSM_MGRP_HOLDER_H_
+#define _OSM_MGRP_HOLDER_H_
+
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_fleximap.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_spinlock.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_mtree.h>
+#include <opensm/osm_mcm_port.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_log.h>
+
+#ifdef __cplusplus
+#  define BEGIN_C_DECLS extern "C" {
+#  define END_C_DECLS   }
+#else				/* !__cplusplus */
+#  define BEGIN_C_DECLS
+#  define END_C_DECLS
+#endif				/* __cplusplus */
+
+BEGIN_C_DECLS
+
+
+
+/****s* OpenSM: Multicast Group/osm_mgrp_holder_t
+* NAME
+*	osm_mgrp_holder_t
+*
+* DESCRIPTION
+*	Holder for mgroup.
+*
+*	The osm_mgrp_t object should be treated as opaque and should
+*	be manipulated only through the provided functions.
+*
+* SYNOPSIS 
+*/
+
+typedef struct osm_mgrp_holder {
+	cl_fmap_t	  mgrp_map;
+    cl_qmap_t		mgrp_port_map;
+	ib_gid_t		common_mgid;
+	osm_mtree_node_t *p_root;
+	boolean_t	 to_be_deleted;
+    uint32_t	last_tree_id;
+	uint32_t	last_change_id;
+	ib_net16_t mlid;
+} osm_mgrp_holder_t;
+
+/*
+* FIELDS
+*	mgrp_map
+*		Map for mgroups.  Must be first element!!
+*
+*	mgrp_port_map
+*		Map of  all ports joined same mlid
+*	common_mgid
+*		mgid of mgroup, ANDed with bitmask.
+*       mgid of each mgroup in mgrp_map, ANDed with bitmask,
+*       see osm_mgrp_holder_prepare_common_mgid
+*
+*	p_root
+*		Pointer to the root "tree node" in the single spanning tree
+*		for this multicast group holder.  The nodes of the tree represent
+*		switches.  Member ports are not represented in the tree.
+*
+*	to_be_deleted
+*		Since holders  are deleted when there are no mgroups in.
+*
+*	last_change_id
+*		a counter for the number of changes applied to the group in this holder.
+*		This counter shuold be incremented on any modification
+*		to the group: joining or leaving of ports.
+*
+*	last_tree_id
+*		the last change id used for building the current tree.
+*
+*/
+ /****s* OpenSM: Multicast Group/osm_mgrp_port _t
+* NAME
+*	osm_mgrp_port _t
+*
+* DESCRIPTION
+*	Holder for mgroups and port guid.
+*
+*
+* SYNOPSIS 
+*/
+typedef struct _osm_mgrp_port {
+	cl_map_item_t guid_item;
+	cl_qlist_t	       mgroups;
+	ib_net64_t 	    	port_guid;
+} osm_mgrp_port_t;
+/*
+* FIELDS
+*	guid_item
+*		Map for ports. Must be first element
+*	mgroups
+*		Map  for  mgroups opened by this port. 
+*
+*	portguid
+*		
+*/
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_new
+* NAME
+*	osm_mgrp_holder_new
+*
+* DESCRIPTION
+*	Allocates and initializes a Multicast Group Holder for use.
+*
+* SYNOPSIS
+*/
+osm_mgrp_holder_t	*osm_mgrp_holder_new(IN osm_subn_t *p_subn, IN ib_gid_t * p_mgid, IN ib_net16_t mlid);
+/*
+* PARAMETERS
+*	p_subn
+*		(in) pointer to osm_subnet
+*	p_mgid
+*		(in)  pointer to  mgid
+*	mlid
+*		[in] Multicast LID for this multicast group holder.
+*
+* RETURN VALUES
+*	pointer to initialized osm_mgrp_holder_t
+*	or NULL, if unsuccessful
+*
+* SEE ALSO
+*	Multicast Group Holder, osm_mgrp_holder_delete
+*********/
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_delete
+* NAME
+*	osm_mgrp_holder_delete
+*
+* DESCRIPTION
+*	Removes  entry from  array of holders
+*	Removes port from mgroup port list
+*	
+* SYNOPSIS
+*/
+void osm_mgrp_holder_delete(IN osm_subn_t * p_subn, IN ib_net16_t mlid);
+/*
+* PARAMETERS
+*
+*  p_subn
+*     [in] Pointer to  osm_subnet
+*
+*  mlid
+*     [in] holder's mlid
+*
+* RETURN VALUES
+*	None.
+*
+* NOTES
+*
+* SEE ALSO
+*	
+*********/
+
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_add_mgrp_port
+* NAME
+*	osm_mgrp_holder_add_mgrp_port
+*
+* DESCRIPTION
+*	Allocates  osm_mgrp_port_t for new port joined to mgroup with mlid of this holder,
+*	(or / and) adds mgroup to mgroup map of  existed osm_mgrp_port_t object.
+*	
+* SYNOPSIS
+*/
+ib_api_status_t osm_mgrp_holder_add_mgrp_port(IN osm_mgrp_holder_t *p_mgrp_holder, IN osm_mgrp_t *p_mgrp,
+				IN ib_net64_t port_guid);
+/*
+* PARAMETERS
+*	p_mgrp_holder 
+*		(in) pointer to osm_mgrp_holder_t
+*	p_mgrp
+*		(in)  pointer to  osm_mgrp_t 
+*
+* RETURN VALUES
+*	IB_SUCCESS or 
+*	IB_INSUFFICIENT_MEMORY
+*
+* SEE ALSO
+*	Multicast Group Holder, osm_mgrp_holder_delete_mgrp_port
+*********/
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_delete_mgrp_port
+* NAME
+*	osm_mgrp_holder_delete_mgrp_port
+*
+* DESCRIPTION
+*	Deletes  osm_mgrp_port_t for specified port
+*	
+* SYNOPSIS
+*/
+void osm_mgrp_holder_delete_mgrp_port(IN osm_mgrp_holder_t *p_mgrp_holder, IN osm_mgrp_t *p_mgrp, 
+				IN ib_net64_t port_guid);
+/*
+* PARAMETERS
+*	p_mgrp_holder
+*		[in] Pointer to an osm_mgrp_holder_t object.
+*
+*	p_mgrp
+*		(in) Pointer to osm_mgrp_t object
+*
+*	port_guid
+*		[in] Port guid of the departing port.
+*
+* RETURN VALUES
+*	None.
+*
+* NOTES
+*
+* SEE ALSO
+	Multicast Group Holder,osm_holder_add_mgrp_port
+*********/
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_remove_port
+* NAME
+*	osm_mgrp_holder_remove_port
+*
+* DESCRIPTION
+*	Removes  osm_mgrp_port_t from mgrp_port_map of holder
+*	Removes port from mgroup port list
+*	
+* SYNOPSIS
+*/
+void osm_mgrp_holder_remove_port(IN osm_subn_t * const p_subn,
+		     IN osm_log_t * const p_log,
+		     IN osm_mgrp_holder_t * const p_mgrp_holder,
+		     IN const ib_net64_t port_guid);
+/*
+* PARAMETERS
+*
+*  p_subn
+*     [in] Pointer to the subnet object
+*
+*  p_log
+*     [in] The log object pointer
+*
+*	p_mgrp_holder
+*		[in] Pointer to an osm_mgrp_holder_t object.
+*
+*	port_guid
+*		[in] Port guid of the departing port.
+*
+* RETURN VALUES
+*	None.
+*
+* NOTES
+*
+* SEE ALSO
+*	
+*********/
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_add_mgrp
+* NAME
+*	osm_mgrp_holder_add_mgrp
+*
+* DESCRIPTION
+*	Adds mgroup to holder according to its mgid
+*	
+*	
+* SYNOPSIS
+*/
+void osm_mgrp_holder_add_mgrp(IN osm_mgrp_holder_t * p_mgrp_holder, 
+							  IN osm_mgrp_t *p_mgrp,
+							  IN osm_log_t * const p_log);
+/*
+* PARAMETERS
+*
+*	p_mgrp_holder
+*		[in] Pointer to an osm_mgrp_holder_t object.
+*
+*	p_mgrp
+*		[in] mgroup to add.
+*
+* RETURN VALUES
+*	None.
+*
+* NOTES
+* Updates common_mgid when holder is being reused
+* SEE ALSO
+*	Multicast Group Holder,osm_mgrp_holder_delete_mgrp
+*********/
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_delete_mgrp
+* NAME
+*	osm_mgrp_holder_delete_mgrp
+*
+* DESCRIPTION
+*	Deletes mgroup from holder according to its mgid
+*	
+*	
+* SYNOPSIS
+*/
+void osm_mgrp_holder_delete_mgrp(IN osm_mgrp_holder_t *p_mgrp_holder,
+								  IN osm_mgrp_t *p_mgrp);
+/*
+* PARAMETERS
+*
+*	p_mgrp_holder
+*		[in] Pointer to an osm_mgrp_holder_t object.
+*
+*	p_mgrp
+*		[in] mgroup to delete.
+*
+* RETURN VALUES
+*	None.
+*
+* NOTES
+*
+* SEE ALSO
+*	Multicast Group Holder,osm_mgrp_holder_add_mgrp
+*********/
+
+
+
+
+/*	Multicast Group Holder, osm_mgrp_holder_delete_port
+*********/
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_prepare_common_mgid
+* NAME
+*	osm_mgrp_holder_prepare_common_mgid
+*
+* DESCRIPTION
+*	Prepares mgid, which is common for all mgroups in this holder
+*	
+* SYNOPSIS
+*/
+void osm_mgrp_holder_prepare_common_mgid(IN const ib_gid_t *const p_mgid, OUT ib_gid_t *p_common_mgid);
+/*
+* PARAMETERS
+*
+*  p_mgid
+*     [in] Pointer to  mgid
+*
+*  p_common_mgid
+*     [out] common mgid
+*
+* RETURN VALUES
+*	None.
+*
+* NOTES
+*
+* SEE ALSO
+*	
+*********/
+
+/****f* OpenSM: Multicast Group Holder /osm_mgrp_holder_get_mlid_by_mgid
+* NAME
+*	osm_mgrp_holder_get_mlid_by_mgid
+*
+* DESCRIPTION
+*	Searches holder which contains mgroup with given mgid
+*	Returns mlid of the found holder
+*	
+* SYNOPSIS
+*/
+ib_net16_t osm_mgrp_holder_get_mlid_by_mgid(IN osm_sa_t * sa, IN const ib_gid_t *const p_mgid);
+/*
+* PARAMETERS
+*
+*  p_sa
+*     [in] Pointer to  sa object
+*
+*  p_mgid
+*     [in] pointer to mgid
+*
+* RETURN VALUES
+*	mlid of found holder, or zero.
+*
+* NOTES
+*
+* SEE ALSO
+*	
+*********/
+
+static inline ib_net16_t osm_mgrp_holder_get_mlid(IN osm_mgrp_holder_t * const p_mgrp_holder)
+{
+	return (p_mgrp_holder->mlid);
+}
+
+static inline boolean_t osm_mgrp_holder_is_empty(IN const osm_mgrp_holder_t * const p_mgrp_holder)
+{
+	return (cl_qmap_count(&p_mgrp_holder->mgrp_port_map) == 0);
+}
+#endif
+
diff --git a/opensm/include/opensm/osm_multicast.h b/opensm/include/opensm/osm_multicast.h
index a871306..b59f06e 100644
--- a/opensm/include/opensm/osm_multicast.h
+++ b/opensm/include/opensm/osm_multicast.h
@@ -44,6 +44,7 @@
 #define _OSM_MULTICAST_H_
 
 #include <iba/ib_types.h>
+#include <complib/cl_fleximap.h>
 #include <complib/cl_qmap.h>
 #include <complib/cl_qlist.h>
 #include <complib/cl_spinlock.h>
@@ -107,6 +108,7 @@ typedef struct osm_mcast_mgr_ctxt {
 * SEE ALSO
 *********/
 
+
 /****s* OpenSM: Multicast Group/osm_mgrp_t
 * NAME
 *	osm_mgrp_t
@@ -117,12 +119,13 @@ typedef struct osm_mcast_mgr_ctxt {
 *	The osm_mgrp_t object should be treated as opaque and should
 *	be manipulated only through the provided functions.
 *
-* SYNOPSIS
+* SYNOPSIS 
 */
 typedef struct osm_mgrp {
+	cl_fmap_item_t mgid_item;
+	cl_list_item_t mgrp_item;
 	cl_map_item_t map_item;
 	ib_net16_t mlid;
-	osm_mtree_node_t *p_root;
 	cl_qmap_t mcm_port_tbl;
 	ib_member_rec_t mcmember_rec;
 	boolean_t well_known;
@@ -140,11 +143,6 @@ typedef struct osm_mgrp {
 *		The network ordered LID of this Multicast Group (must be
 *		>= 0xC000).
 *
-*	p_root
-*		Pointer to the root "tree node" in the single spanning tree
-*		for this multicast group.  The nodes of the tree represent
-*		switches.  Member ports are not represented in the tree.
-*
 *	mcm_port_tbl
 *		Table (sorted by port GUID) of osm_mcm_port_t objects
 *		representing the member ports of this multicast group.
@@ -239,7 +237,8 @@ osm_mgrp_t *osm_mgrp_new(IN const ib_net16_t mlid);
 *
 * SYNOPSIS
 */
-void osm_mgrp_delete(IN osm_mgrp_t * const p_mgrp);
+void osm_mgrp_delete(IN osm_subn_t * p_subn,
+					 IN osm_mgrp_t *const p_mgrp);
 /*
 * PARAMETERS
 *	p_mgrp
diff --git a/opensm/include/opensm/osm_sm.h b/opensm/include/opensm/osm_sm.h
index cc8321d..e828505 100644
--- a/opensm/include/opensm/osm_sm.h
+++ b/opensm/include/opensm/osm_sm.h
@@ -61,6 +61,7 @@
 #include <opensm/osm_port.h>
 #include <opensm/osm_db.h>
 #include <opensm/osm_remote_sm.h>
+#include <opensm/osm_multicast.h>
 
 #ifdef __cplusplus
 #  define BEGIN_C_DECLS extern "C" {
@@ -539,7 +540,8 @@ osm_resp_send(IN osm_sm_t * sm,
 ib_api_status_t
 osm_sm_mcgrp_join(IN osm_sm_t * const p_sm,
 		  IN const ib_net16_t mlid,
-		  IN const ib_net64_t port_guid);
+		  IN const ib_net64_t port_guid,
+		  IN const ib_gid_t *p_mgid);
 /*
 * PARAMETERS
 *	p_sm
@@ -551,6 +553,8 @@ osm_sm_mcgrp_join(IN osm_sm_t * const p_sm,
 *	port_guid
 *		[in] Port GUID to add to the group.
 *
+*   p_mgid
+*		[in] MGID to add to the group holder.
 * RETURN VALUES
 *	None
 *
@@ -572,7 +576,7 @@ osm_sm_mcgrp_join(IN osm_sm_t * const p_sm,
 */
 ib_api_status_t
 osm_sm_mcgrp_leave(IN osm_sm_t * const p_sm,
-		   IN const ib_net16_t mlid, IN const ib_net64_t port_guid);
+		   IN osm_mgrp_t *p_mgrp, IN ib_net64_t port_guid);
 /*
 * PARAMETERS
 *	p_sm
diff --git a/opensm/include/opensm/osm_subnet.h b/opensm/include/opensm/osm_subnet.h
index 59a32ad..329c5a8 100644
--- a/opensm/include/opensm/osm_subnet.h
+++ b/opensm/include/opensm/osm_subnet.h
@@ -508,7 +508,7 @@ typedef struct osm_subn {
 	boolean_t first_time_master_sweep;
 	boolean_t coming_out_of_standby;
 	unsigned need_update;
-	void *mgroups[IB_LID_MCAST_END_HO - IB_LID_MCAST_START_HO + 1];
+	void *mgroup_holders[IB_LID_MCAST_END_HO - IB_LID_MCAST_START_HO + 1];
 } osm_subn_t;
 /*
 * FIELDS
@@ -942,9 +942,9 @@ struct osm_port *osm_get_port_by_guid(IN osm_subn_t const *p_subn,
 * SYNOPSIS
 */
 static inline
-struct osm_mgrp *osm_get_mgrp_by_mlid(osm_subn_t const *p_subn, ib_net16_t mlid)
+struct osm_mgrp_holder *osm_get_mgrp_holder_by_mlid(osm_subn_t const *p_subn, ib_net16_t mlid)
 {
-	return p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO];
+	return p_subn->mgroup_holders[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO];
 }
 /*
 * PARAMETERS
diff --git a/opensm/opensm/Makefile.am b/opensm/opensm/Makefile.am
index 2d67a95..9a4d2a6 100644
--- a/opensm/opensm/Makefile.am
+++ b/opensm/opensm/Makefile.am
@@ -52,6 +52,7 @@ opensm_SOURCES = main.c osm_console_io.c osm_console.c osm_db_files.c \
 		 osm_subnet.c osm_sw_info_rcv.c osm_switch.c \
 		 osm_prtn.c osm_prtn_config.c osm_qos.c osm_router.c \
 		 osm_trap_rcv.c osm_ucast_mgr.c osm_ucast_updn.c \
+		 osm_mgrp_holder.c \
 		 osm_ucast_lash.c osm_ucast_file.c osm_ucast_ftree.c \
 		 osm_vl15intf.c osm_vl_arb_rcv.c \
 		 st.c osm_perfmgr.c osm_perfmgr_db.c \
diff --git a/opensm/opensm/osm_drop_mgr.c b/opensm/opensm/osm_drop_mgr.c
index c9a4f33..8becc2c 100644
--- a/opensm/opensm/osm_drop_mgr.c
+++ b/opensm/opensm/osm_drop_mgr.c
@@ -62,6 +62,7 @@
 #include <opensm/osm_remote_sm.h>
 #include <opensm/osm_inform.h>
 #include <opensm/osm_ucast_mgr.h>
+#include <opensm/osm_mgrp_holder.h>
 
 /**********************************************************************
  **********************************************************************/
@@ -158,7 +159,6 @@ static void drop_mgr_remove_port(osm_sm_t * sm, IN osm_port_t * p_port)
 	osm_port_t *p_port_check;
 	cl_qmap_t *p_sm_guid_tbl;
 	osm_mcm_info_t *p_mcm;
-	osm_mgrp_t *p_mgrp;
 	cl_ptr_vector_t *p_port_lid_tbl;
 	uint16_t min_lid_ho;
 	uint16_t max_lid_ho;
@@ -168,6 +168,7 @@ static void drop_mgr_remove_port(osm_sm_t * sm, IN osm_port_t * p_port)
 	ib_gid_t port_gid;
 	ib_mad_notice_attr_t notice;
 	ib_api_status_t status;
+	osm_mgrp_holder_t *p_osm_mgrp_holder;
 
 	OSM_LOG_ENTER(sm->p_log);
 
@@ -212,10 +213,10 @@ static void drop_mgr_remove_port(osm_sm_t * sm, IN osm_port_t * p_port)
 
 	p_mcm = (osm_mcm_info_t *) cl_qlist_remove_head(&p_port->mcm_list);
 	while (p_mcm != (osm_mcm_info_t *) cl_qlist_end(&p_port->mcm_list)) {
-		p_mgrp = osm_get_mgrp_by_mlid(sm->p_subn, p_mcm->mlid);
-		if (p_mgrp) {
-			osm_mgrp_delete_port(sm->p_subn, sm->p_log,
-					     p_mgrp, p_port->guid);
+		p_osm_mgrp_holder = osm_get_mgrp_holder_by_mlid(sm->p_subn, p_mcm->mlid);
+		if (p_osm_mgrp_holder) {
+			osm_mgrp_holder_remove_port(sm->p_subn, sm->p_log,
+					     p_osm_mgrp_holder, p_port->guid);
 			osm_mcm_info_delete((osm_mcm_info_t *) p_mcm);
 		}
 		p_mcm =
diff --git a/opensm/opensm/osm_mcast_mgr.c b/opensm/opensm/osm_mcast_mgr.c
index de0a8a5..9a4adae 100644
--- a/opensm/opensm/osm_mcast_mgr.c
+++ b/opensm/opensm/osm_mcast_mgr.c
@@ -55,6 +55,8 @@
 #include <opensm/osm_switch.h>
 #include <opensm/osm_helper.h>
 #include <opensm/osm_msgdef.h>
+#include <opensm/osm_mgrp_holder.h>
+#include <arpa/inet.h>
 
 /**********************************************************************
  **********************************************************************/
@@ -111,14 +113,14 @@ static void mcast_mgr_purge_tree_node(IN osm_mtree_node_t * p_mtn)
 
 /**********************************************************************
  **********************************************************************/
-static void mcast_mgr_purge_tree(osm_sm_t * sm, IN osm_mgrp_t * p_mgrp)
+static void mcast_mgr_purge_tree(osm_sm_t * sm, IN osm_mgrp_holder_t * p_mgrp_holder)
 {
 	OSM_LOG_ENTER(sm->p_log);
 
-	if (p_mgrp->p_root)
-		mcast_mgr_purge_tree_node(p_mgrp->p_root);
+	if (p_mgrp_holder->p_root)
+		mcast_mgr_purge_tree_node(p_mgrp_holder->p_root);
 
-	p_mgrp->p_root = NULL;
+	p_mgrp_holder->p_root = NULL;
 
 	OSM_LOG_EXIT(sm->p_log);
 }
@@ -126,41 +128,37 @@ static void mcast_mgr_purge_tree(osm_sm_t * sm, IN osm_mgrp_t * p_mgrp)
 /**********************************************************************
  **********************************************************************/
 static float osm_mcast_mgr_compute_avg_hops(osm_sm_t * sm,
-					    const osm_mgrp_t * p_mgrp,
+					    const osm_mgrp_holder_t * p_mgrp_holder,
 					    const osm_switch_t * p_sw)
 {
 	float avg_hops = 0;
 	uint32_t hops = 0;
 	uint32_t num_ports = 0;
 	const osm_port_t *p_port;
-	const osm_mcm_port_t *p_mcm_port;
-	const cl_qmap_t *p_mcm_tbl;
+	const osm_mgrp_port_t *p_holder_port;
 
 	OSM_LOG_ENTER(sm->p_log);
 
-	p_mcm_tbl = &p_mgrp->mcm_port_tbl;
 
 	/*
 	   For each member of the multicast group, compute the
 	   number of hops to its base LID.
 	 */
-	for (p_mcm_port = (osm_mcm_port_t *) cl_qmap_head(p_mcm_tbl);
-	     p_mcm_port != (osm_mcm_port_t *) cl_qmap_end(p_mcm_tbl);
-	     p_mcm_port =
-	     (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item)) {
+	for (p_holder_port = (osm_mgrp_port_t *) cl_qmap_head(&p_mgrp_holder->mgrp_port_map);
+	     p_holder_port != (osm_mgrp_port_t *) cl_qmap_end(&p_mgrp_holder->mgrp_port_map);
+	     p_holder_port =
+	     (osm_mgrp_port_t *) cl_qmap_next(&p_holder_port->guid_item)) {
 		/*
 		   Acquire the port object for this port guid, then create
 		   the new worker object to build the list.
 		 */
 		p_port = osm_get_port_by_guid(sm->p_subn,
-					      ib_gid_get_guid(&p_mcm_port->
-							      port_gid));
+					      p_holder_port->port_guid);
 
 		if (!p_port) {
 			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A18: "
 				"No port object for port 0x%016" PRIx64 "\n",
-				cl_ntoh64(ib_gid_get_guid
-					  (&p_mcm_port->port_gid)));
+				cl_ntoh64(p_holder_port->port_guid));
 			continue;
 		}
 
@@ -185,40 +183,35 @@ static float osm_mcast_mgr_compute_avg_hops(osm_sm_t * sm,
  of the group HCAs
  **********************************************************************/
 static float osm_mcast_mgr_compute_max_hops(osm_sm_t * sm,
-					    const osm_mgrp_t * p_mgrp,
+					    const osm_mgrp_holder_t * p_mgrp_holder,
 					    const osm_switch_t * p_sw)
 {
 	uint32_t max_hops = 0;
 	uint32_t hops = 0;
 	const osm_port_t *p_port;
-	const osm_mcm_port_t *p_mcm_port;
-	const cl_qmap_t *p_mcm_tbl;
+	const osm_mgrp_port_t *p_mgrp_holder_port;
 
 	OSM_LOG_ENTER(sm->p_log);
 
-	p_mcm_tbl = &p_mgrp->mcm_port_tbl;
 
 	/*
 	   For each member of the multicast group, compute the
 	   number of hops to its base LID.
 	 */
-	for (p_mcm_port = (osm_mcm_port_t *) cl_qmap_head(p_mcm_tbl);
-	     p_mcm_port != (osm_mcm_port_t *) cl_qmap_end(p_mcm_tbl);
-	     p_mcm_port =
-	     (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item)) {
+	for (p_mgrp_holder_port = (osm_mgrp_port_t *) cl_qmap_head(&p_mgrp_holder->mgrp_port_map);
+	     p_mgrp_holder_port != (osm_mgrp_port_t *) cl_qmap_end(&p_mgrp_holder->mgrp_port_map);
+	     p_mgrp_holder_port =
+	     (osm_mgrp_port_t *) cl_qmap_next(&p_mgrp_holder_port->guid_item)) {
 		/*
 		   Acquire the port object for this port guid, then create
 		   the new worker object to build the list.
 		 */
 		p_port = osm_get_port_by_guid(sm->p_subn,
-					      ib_gid_get_guid(&p_mcm_port->
-							      port_gid));
-
+					      p_mgrp_holder_port->port_guid);
 		if (!p_port) {
 			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A1A: "
 				"No port object for port 0x%016" PRIx64 "\n",
-				cl_ntoh64(ib_gid_get_guid
-					  (&p_mcm_port->port_gid)));
+				cl_ntoh64(p_mgrp_holder_port->port_guid));
 			continue;
 		}
 
@@ -244,15 +237,15 @@ static float osm_mcast_mgr_compute_max_hops(osm_sm_t * sm,
    of the multicast group.
 **********************************************************************/
 static osm_switch_t *mcast_mgr_find_optimal_switch(osm_sm_t * sm,
-						   const osm_mgrp_t * p_mgrp)
+						   const osm_mgrp_holder_t *p_mgrp_holder)
 {
 	cl_qmap_t *p_sw_tbl;
-	const osm_switch_t *p_sw;
-	const osm_switch_t *p_best_sw = NULL;
+	osm_switch_t *p_sw;
+	osm_switch_t *p_best_sw = NULL;
 	float hops = 0;
 	float best_hops = 10000;	/* any big # will do */
 #ifdef OSM_VENDOR_INTF_ANAFA
-	boolean_t use_avg_hops = TRUE;	/* anafa2 - bug hca on switch *//* use max hops for root */
+	boolean_t use_avg_hops = TRUE;	/* anafa2 - bug hca on switch - use max hops for root */
 #else
 	boolean_t use_avg_hops = FALSE;	/* use max hops for root */
 #endif
@@ -260,8 +253,7 @@ static osm_switch_t *mcast_mgr_find_optimal_switch(osm_sm_t * sm,
 	OSM_LOG_ENTER(sm->p_log);
 
 	p_sw_tbl = &sm->p_subn->sw_guid_tbl;
-
-	CL_ASSERT(!osm_mgrp_is_empty(p_mgrp));
+	CL_ASSERT(!osm_mgrp_holder_is_empty(p_mgrp_holder));
 
 	for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl);
 	     p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl);
@@ -270,13 +262,13 @@ static osm_switch_t *mcast_mgr_find_optimal_switch(osm_sm_t * sm,
 			continue;
 
 		if (use_avg_hops)
-			hops = osm_mcast_mgr_compute_avg_hops(sm, p_mgrp, p_sw);
+			hops = osm_mcast_mgr_compute_avg_hops(sm, p_mgrp_holder, p_sw);
 		else
-			hops = osm_mcast_mgr_compute_max_hops(sm, p_mgrp, p_sw);
+			hops = osm_mcast_mgr_compute_max_hops(sm, p_mgrp_holder, p_sw);
 
 		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
-			"Switch 0x%016" PRIx64 ", hops = %f\n",
-			cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), hops);
+		    "Switch 0x%016" PRIx64 ", hops = %f\n",
+         	    cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), hops);
 
 		if (hops < best_hops) {
 			p_best_sw = p_sw;
@@ -301,7 +293,7 @@ static osm_switch_t *mcast_mgr_find_optimal_switch(osm_sm_t * sm,
    This function returns the existing or optimal root swtich for the tree.
 **********************************************************************/
 static osm_switch_t *mcast_mgr_find_root_switch(osm_sm_t * sm,
-						const osm_mgrp_t * p_mgrp)
+						const osm_mgrp_holder_t * p_mgrp_holder)
 {
 	const osm_switch_t *p_sw = NULL;
 
@@ -313,7 +305,7 @@ static osm_switch_t *mcast_mgr_find_root_switch(osm_sm_t * sm,
 	   the root will be always on the first switch attached to it.
 	   - Very bad ...
 	 */
-	p_sw = mcast_mgr_find_optimal_switch(sm, p_mgrp);
+	p_sw = mcast_mgr_find_optimal_switch(sm, p_mgrp_holder);
 
 	OSM_LOG_EXIT(sm->p_log);
 	return (osm_switch_t *) p_sw;
@@ -394,7 +386,7 @@ static osm_signal_t mcast_mgr_set_tbl(osm_sm_t * sm, IN osm_switch_t * p_sw)
   spanning tree that eminate from this switch.  On input, the p_list
   contains the group members that must be routed from this switch.
 **********************************************************************/
-static void mcast_mgr_subdivide(osm_sm_t * sm, osm_mgrp_t * p_mgrp,
+static void mcast_mgr_subdivide(osm_sm_t * sm, osm_mgrp_holder_t * p_mgrp_holder,
 				osm_switch_t * p_sw, cl_qlist_t * p_list,
 				cl_qlist_t * list_array, uint8_t array_size)
 {
@@ -405,7 +397,7 @@ static void mcast_mgr_subdivide(osm_sm_t * sm, osm_mgrp_t * p_mgrp,
 
 	OSM_LOG_ENTER(sm->p_log);
 
-	mlid_ho = cl_ntoh16(osm_mgrp_get_mlid(p_mgrp));
+	mlid_ho = cl_ntoh16(osm_mgrp_holder_get_mlid(p_mgrp_holder));
 
 	/*
 	   For Multicast Groups, we want not to count on previous
@@ -495,7 +487,7 @@ static void mcast_mgr_purge_list(osm_sm_t * sm, cl_qlist_t * p_list)
 
   The function returns the newly created mtree node element.
 **********************************************************************/
-static osm_mtree_node_t *mcast_mgr_branch(osm_sm_t * sm, osm_mgrp_t * p_mgrp,
+static osm_mtree_node_t *mcast_mgr_branch(osm_sm_t * sm, osm_mgrp_holder_t * p_mgrp_holder,
 					  osm_switch_t * p_sw,
 					  cl_qlist_t * p_list, uint8_t depth,
 					  uint8_t upstream_port,
@@ -521,7 +513,7 @@ static osm_mtree_node_t *mcast_mgr_branch(osm_sm_t * sm, osm_mgrp_t * p_mgrp,
 
 	node_guid = osm_node_get_node_guid(p_sw->p_node);
 	node_guid_ho = cl_ntoh64(node_guid);
-	mlid_ho = cl_ntoh16(osm_mgrp_get_mlid(p_mgrp));
+	mlid_ho = cl_ntoh16(osm_mgrp_holder_get_mlid(p_mgrp_holder));
 
 	OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
 		"Routing MLID 0x%X through switch 0x%" PRIx64
@@ -598,7 +590,7 @@ static osm_mtree_node_t *mcast_mgr_branch(osm_sm_t * sm, osm_mgrp_t * p_mgrp,
 	for (i = 0; i < max_children; i++)
 		cl_qlist_init(&list_array[i]);
 
-	mcast_mgr_subdivide(sm, p_mgrp, p_sw, p_list, list_array, max_children);
+	mcast_mgr_subdivide(sm, p_mgrp_holder, p_sw, p_list, list_array, max_children);
 
 	p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw);
 
@@ -681,7 +673,7 @@ static osm_mtree_node_t *mcast_mgr_branch(osm_sm_t * sm, osm_mgrp_t * p_mgrp,
 			CL_ASSERT(p_remote_physp);
 
 			p_mtn->child_array[i] =
-			    mcast_mgr_branch(sm, p_mgrp, p_remote_node->sw,
+			    mcast_mgr_branch(sm, p_mgrp_holder, p_remote_node->sw,
 					     p_port_list, depth,
 					     osm_physp_get_port_num
 					     (p_remote_physp), p_max_depth);
@@ -717,11 +709,10 @@ Exit:
 /**********************************************************************
  **********************************************************************/
 static ib_api_status_t mcast_mgr_build_spanning_tree(osm_sm_t * sm,
-						     osm_mgrp_t * p_mgrp)
+						     osm_mgrp_holder_t * p_mgrp_holder)
 {
-	const cl_qmap_t *p_mcm_tbl;
 	const osm_port_t *p_port;
-	const osm_mcm_port_t *p_mcm_port;
+	const osm_mgrp_port_t *p_mgrp_port;
 	uint32_t num_ports;
 	cl_qlist_t port_list;
 	osm_switch_t *p_sw;
@@ -740,14 +731,13 @@ static ib_api_status_t mcast_mgr_build_spanning_tree(osm_sm_t * sm,
 	   on multicast forwarding table information if the user wants to
 	   preserve existing multicast routes.
 	 */
-	mcast_mgr_purge_tree(sm, p_mgrp);
+	mcast_mgr_purge_tree(sm, p_mgrp_holder);
 
-	p_mcm_tbl = &p_mgrp->mcm_port_tbl;
-	num_ports = cl_qmap_count(p_mcm_tbl);
+	num_ports = cl_qmap_count(&p_mgrp_holder->mgrp_port_map);
 	if (num_ports == 0) {
 		OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
 			"MLID 0x%X has no members - nothing to do\n",
-			cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)));
+			cl_ntoh16(osm_mgrp_holder_get_mlid(p_mgrp_holder)));
 		goto Exit;
 	}
 
@@ -767,11 +757,11 @@ static ib_api_status_t mcast_mgr_build_spanning_tree(osm_sm_t * sm,
 	   Locate the switch around which to create the spanning
 	   tree for this multicast group.
 	 */
-	p_sw = mcast_mgr_find_root_switch(sm, p_mgrp);
+	p_sw = mcast_mgr_find_root_switch(sm, p_mgrp_holder);
 	if (p_sw == NULL) {
 		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A08: "
 			"Unable to locate a suitable switch for group 0x%X\n",
-			cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)));
+			cl_ntoh16(osm_mgrp_holder_get_mlid(p_mgrp_holder)));
 		status = IB_ERROR;
 		goto Exit;
 	}
@@ -779,22 +769,19 @@ static ib_api_status_t mcast_mgr_build_spanning_tree(osm_sm_t * sm,
 	/*
 	   Build the first "subset" containing all member ports.
 	 */
-	for (p_mcm_port = (osm_mcm_port_t *) cl_qmap_head(p_mcm_tbl);
-	     p_mcm_port != (osm_mcm_port_t *) cl_qmap_end(p_mcm_tbl);
-	     p_mcm_port =
-	     (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item)) {
+	for (p_mgrp_port = (osm_mgrp_port_t *) cl_qmap_head(&p_mgrp_holder->mgrp_port_map);
+	     p_mgrp_port != (osm_mgrp_port_t *) cl_qmap_end(&p_mgrp_holder->mgrp_port_map);
+	     p_mgrp_port =
+	     (osm_mgrp_port_t *) cl_qmap_next(&p_mgrp_port->guid_item)) {
 		/*
 		   Acquire the port object for this port guid, then create
 		   the new worker object to build the list.
 		 */
-		p_port = osm_get_port_by_guid(sm->p_subn,
-					      ib_gid_get_guid(&p_mcm_port->
-							      port_gid));
+		p_port = osm_get_port_by_guid(sm->p_subn, p_mgrp_port->port_guid);
 		if (!p_port) {
 			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A09: "
 				"No port object for port 0x%016" PRIx64 "\n",
-				cl_ntoh64(ib_gid_get_guid
-					  (&p_mcm_port->port_gid)));
+				cl_ntoh64(p_mgrp_port->port_guid));
 			continue;
 		}
 
@@ -803,7 +790,7 @@ static ib_api_status_t mcast_mgr_build_spanning_tree(osm_sm_t * sm,
 			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A10: "
 				"Insufficient memory to route port 0x%016"
 				PRIx64 "\n",
-				cl_ntoh64(osm_port_get_guid(p_port)));
+				cl_ntoh64(p_mgrp_port->port_guid));
 			continue;
 		}
 
@@ -811,12 +798,12 @@ static ib_api_status_t mcast_mgr_build_spanning_tree(osm_sm_t * sm,
 	}
 
 	count = cl_qlist_count(&port_list);
-	p_mgrp->p_root = mcast_mgr_branch(sm, p_mgrp, p_sw, &port_list, 0, 0,
+	p_mgrp_holder->p_root = mcast_mgr_branch(sm, p_mgrp_holder, p_sw, &port_list, 0, 0,
 					  &max_depth);
 
 	OSM_LOG(sm->p_log, OSM_LOG_VERBOSE,
 		"Configured MLID 0x%X for %u ports, max tree depth = %u\n",
-		cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)), count, max_depth);
+		cl_ntoh16(osm_mgrp_holder_get_mlid(p_mgrp_holder)), count, max_depth);
 
 Exit:
 	OSM_LOG_EXIT(sm->p_log);
@@ -1023,14 +1010,16 @@ Exit:
    lock must already be held on entry
 **********************************************************************/
 static ib_api_status_t osm_mcast_mgr_process_tree(osm_sm_t * sm,
-						  IN osm_mgrp_t * p_mgrp)
+						  IN osm_mgrp_holder_t * p_mgrp_holder)
 {
 	ib_api_status_t status = IB_SUCCESS;
 	ib_net16_t mlid;
+	osm_mgrp_t *p_mgrp;
+	unsigned has_full_members  = 0;
 
 	OSM_LOG_ENTER(sm->p_log);
 
-	mlid = osm_mgrp_get_mlid(p_mgrp);
+	mlid = osm_mgrp_holder_get_mlid(p_mgrp_holder);
 
 	OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
 		"Processing multicast group 0x%X\n", cl_ntoh16(mlid));
@@ -1051,10 +1040,16 @@ static ib_api_status_t osm_mcast_mgr_process_tree(osm_sm_t * sm,
 	 */
 	mcast_mgr_clear(sm, cl_ntoh16(mlid));
 
-	if (!p_mgrp->full_members)
+	p_mgrp = (osm_mgrp_t*)cl_fmap_head(&p_mgrp_holder->mgrp_map);
+	while (p_mgrp !=  (osm_mgrp_t*)cl_fmap_end(&p_mgrp_holder->mgrp_map)) {
+		if (0 != (has_full_members = p_mgrp->full_members))
+			break;
+		p_mgrp = (osm_mgrp_t*)cl_fmap_next(&p_mgrp->mgid_item);
+	}
+	if (!has_full_members)
 		goto Exit;
 
-	status = mcast_mgr_build_spanning_tree(sm, p_mgrp);
+	status = mcast_mgr_build_spanning_tree(sm, p_mgrp_holder);
 	if (status != IB_SUCCESS) {
 		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A17: "
 			"Unable to create spanning tree (%s)\n",
@@ -1068,33 +1063,56 @@ Exit:
 }
 
 /**********************************************************************
- Process the entire group.
+ Process the entire group holder.
  NOTE : The lock should be held externally!
  **********************************************************************/
 static ib_api_status_t mcast_mgr_process_mgrp(osm_sm_t * sm,
-					      IN osm_mgrp_t * p_mgrp)
+					      IN osm_mgrp_holder_t * p_mgrp_holder)
 {
 	ib_api_status_t status;
+	osm_mgrp_t *p_mgrp;
+	cl_fmap_item_t *p_fitem;
+	ib_net16_t mlid;
+    	char gid_str[INET6_ADDRSTRLEN];
 
 	OSM_LOG_ENTER(sm->p_log);
 
-	status = osm_mcast_mgr_process_tree(sm, p_mgrp);
+	status = osm_mcast_mgr_process_tree(sm, p_mgrp_holder);
 	if (status != IB_SUCCESS) {
 		OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A19: "
 			"Unable to create spanning tree (%s)\n",
 			ib_get_err_str(status));
 		goto Exit;
 	}
-	p_mgrp->last_tree_id = p_mgrp->last_change_id;
-
-	/* remove MCGRP if it is marked for deletion */
-	if (p_mgrp->to_be_deleted) {
+	p_mgrp_holder->last_tree_id = p_mgrp_holder->last_change_id;
+
+	p_fitem = cl_fmap_head(&p_mgrp_holder->mgrp_map);
+	while(p_fitem != cl_fmap_end(&p_mgrp_holder->mgrp_map)) {
+		p_mgrp = (osm_mgrp_t*)p_fitem;
+		mlid = p_mgrp->mlid;
+		p_fitem = cl_fmap_next(p_fitem);
+		if (osm_is_debug()) {
+			OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
+					"holder mlid 0x%X has mgrp mgid = %s\n",
+					 cl_ntoh16(p_mgrp_holder->mlid),
+					 inet_ntop(AF_INET6, p_mgrp->mcmember_rec.mgid.raw, gid_str, sizeof (gid_str)));
+		}
+		/* remove MCGRP if it is marked for deletion */
+		if (p_mgrp->to_be_deleted) {
+			OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
+				"Destroying mgrp  %s with lid:0x%x\n",
+				 inet_ntop(AF_INET6, p_mgrp->mcmember_rec.mgid.raw, gid_str, sizeof (gid_str)),
+			     cl_ntoh16(p_mgrp->mlid));
+			osm_mgrp_delete(sm->p_subn,p_mgrp);
+			p_fitem = cl_fmap_head(&p_mgrp_holder->mgrp_map);
+		}
+	}
+	if (0 == cl_fmap_count(&p_mgrp_holder->mgrp_map)) {
+		/* no more groups on this mlid*/
 		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
-			"Destroying mgrp with lid:0x%x\n",
-			cl_ntoh16(p_mgrp->mlid));
-		sm->p_subn->mgroups[cl_ntoh16(p_mgrp->mlid) -
-				    IB_LID_MCAST_START_HO] = NULL;
-		osm_mgrp_delete(p_mgrp);
+				"Destroying mgrp_holder with lid:0x%x\n",
+				 cl_ntoh16(p_mgrp_holder->mlid));
+		osm_mgrp_holder_delete(sm->p_subn,p_mgrp_holder->mlid);
 	}
 
 Exit:
@@ -1110,7 +1128,7 @@ osm_signal_t osm_mcast_mgr_process(osm_sm_t * sm)
 	osm_switch_t *p_sw;
 	cl_qmap_t *p_sw_tbl;
 	cl_qlist_t *p_list = &sm->mgrp_list;
-	osm_mgrp_t *p_mgrp;
+	osm_mgrp_holder_t *p_mgrp_holder;
 	boolean_t pending_transactions = FALSE;
 	int i;
 
@@ -1132,9 +1150,10 @@ osm_signal_t osm_mcast_mgr_process(osm_sm_t * sm)
 		   of the subnet. Not due to a specific multicast request.
 		   So the request type is subnet_change and the port guid is 0.
 		 */
-		p_mgrp = sm->p_subn->mgroups[i];
-		if (p_mgrp)
-			mcast_mgr_process_mgrp(sm, p_mgrp);
+		p_mgrp_holder = sm->p_subn->mgroup_holders[i];
+		if (p_mgrp_holder) {
+			mcast_mgr_process_mgrp(sm, p_mgrp_holder);
+		}
 	}
 
 	/*
@@ -1172,7 +1191,7 @@ osm_signal_t osm_mcast_mgr_process_mgroups(osm_sm_t * sm)
 	cl_qlist_t *p_list = &sm->mgrp_list;
 	osm_switch_t *p_sw;
 	cl_qmap_t *p_sw_tbl;
-	osm_mgrp_t *p_mgrp;
+	osm_mgrp_holder_t *p_mgrp_holder;
 	ib_net16_t mlid;
 	osm_signal_t ret, signal = OSM_SIGNAL_DONE;
 	osm_mcast_mgr_ctxt_t *ctx;
@@ -1193,24 +1212,24 @@ osm_signal_t osm_mcast_mgr_process_mgroups(osm_sm_t * sm)
 
 		/* since we delayed the execution we prefer to pass the
 		   mlid as the mgrp identifier and then find it or abort */
-		p_mgrp = osm_get_mgrp_by_mlid(sm->p_subn, mlid);
-		if (!p_mgrp)
+		p_mgrp_holder = osm_get_mgrp_holder_by_mlid(sm->p_subn, mlid);
+		if (!p_mgrp_holder)
 			continue;
 
 		/* if there was no change from the last time
 		 * we processed the group we can skip doing anything
 		 */
-		if (p_mgrp->last_change_id == p_mgrp->last_tree_id) {
+		if (p_mgrp_holder->last_change_id == p_mgrp_holder->last_tree_id) {
 			OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
-				"Skip processing mgrp with lid:0x%X change id:%u\n",
-				cl_ntoh16(mlid), p_mgrp->last_change_id);
+				"Skip processing p_mgrp_holder with lid:0x%X change id:%u\n",
+				cl_ntoh16(mlid), p_mgrp_holder->last_change_id);
 			continue;
 		}
 
 		OSM_LOG(sm->p_log, OSM_LOG_DEBUG,
 			"Processing mgrp with lid:0x%X change id:%u\n",
-			cl_ntoh16(mlid), p_mgrp->last_change_id);
-		mcast_mgr_process_mgrp(sm, p_mgrp);
+			cl_ntoh16(mlid), p_mgrp_holder->last_change_id);
+		mcast_mgr_process_mgrp(sm, p_mgrp_holder);
 	}
 
 	/*
diff --git a/opensm/opensm/osm_mgrp_holder.c b/opensm/opensm/osm_mgrp_holder.c
new file mode 100644
index 0000000..9962c3e
--- /dev/null
+++ b/opensm/opensm/osm_mgrp_holder.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+/*
+ * Abstract:
+ *    Implementation of multicast holder functions.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif				/* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_mcm_port.h>
+#include <opensm/osm_mtree.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_mgrp_holder.h>
+/**********************************************************************
+ **********************************************************************/
+#define PREFIX_MASK_IP CL_HTON64(0xff10ffff0000ffffULL)
+#define PREFIX_SIGNATURE_IPV4 CL_HTON64(0xff10401b00000000ULL)
+#define INTERFACE_ID_IPV4            CL_HTON64(0x0000000fffffffffULL)
+#define PREFIX_SIGNATURE_IPV6    		 CL_HTON64(0xff10601b00000000ULL)
+#define INTERFACE_ID_ALL_NODES		 CL_HTON64(0x00000000ffffffffULL)
+#define INTERFACE_ID_ALL_HOSTS		 CL_HTON64(0x0000000000000001ULL)
+#define INTERFACE_ID_ALL_GATEWAYS		 CL_HTON64(0x000000000000004dULL)
+#define INTERFACE_ID_ALL_ROUTERS		 CL_HTON64(0x0000000000000002ULL)
+#define PREFIX_PKEY_MASK_OFF          CL_HTON64(0xffffffff0000ffffULL)
+#define PREFIX_MASK CL_HTON64(0xff10ffff0000ffffULL)
+#define PREFIX_SIGNATURE CL_HTON64(0xff10601b00000000ULL)
+#define INT_ID_MASK CL_HTON64(0xfffffff1ff000000ULL)
+#define INT_ID_SIGNATURE CL_HTON64(0x00000001ff000000ULL)
+
+/**********************************************************************
+ **********************************************************************/
+ /* mask used for multiplexing mgids to one mlid. Here default value (0xff) means that 8 lsb bits
+ of mgid will be masked off .
+ */
+static uint64_t  MGID_MUX_MLID_MASK = CL_HTON64(0x00000000000000ffULL);
+
+void osm_mgrp_holder_prepare_common_mgid(IN const ib_gid_t *const p_mgid, OUT ib_gid_t *p_common_mgid)
+{
+	memcpy(p_common_mgid, p_mgid,sizeof(ib_gid_t));
+	/* Don't mux non IPoIB mgids. When mux mask is zero, no multiplexing occures*/
+	if ( ( (p_common_mgid->unicast.prefix & PREFIX_MASK_IP) != PREFIX_SIGNATURE_IPV4) &&
+		  ((p_common_mgid->unicast.prefix & PREFIX_MASK_IP) != PREFIX_SIGNATURE_IPV6) ||
+		  (  ! MGID_MUX_MLID_MASK))
+		return;
+
+	if ( ( (p_common_mgid->unicast.prefix & PREFIX_MASK_IP) == PREFIX_SIGNATURE_IPV4) &&
+		  ( (p_common_mgid->unicast.interface_id  == INTERFACE_ID_ALL_NODES) ||
+			(p_common_mgid->unicast.interface_id  == INTERFACE_ID_ALL_HOSTS) ||
+			(p_common_mgid->unicast.interface_id  == INTERFACE_ID_ALL_GATEWAYS) ||
+			(p_common_mgid->unicast.interface_id  == INTERFACE_ID_ALL_ROUTERS) )) {
+		/* zero pkey bits - special groups will have same mlid for all PKEYs*/
+		p_common_mgid->unicast.prefix &= PREFIX_PKEY_MASK_OFF;
+	}
+	else if  ((p_common_mgid->unicast.prefix & PREFIX_MASK_IP) == PREFIX_SIGNATURE_IPV6 &&
+	    (p_common_mgid->unicast.interface_id & INT_ID_MASK) == INT_ID_SIGNATURE) {
+		/* Special Case IPv6 Solicited Node Multicast (SNM) addresses */
+		/* 0xff1Z601bXXXX0000 : 0x00000001ffYYYYYY */
+		/* Where Z is the scope, XXXX is the P_Key, and
+		* YYYYYY is the last 24 bits of the port guid */
+		 p_common_mgid->unicast.prefix &= PREFIX_MASK_IP;
+		 p_common_mgid->unicast.interface_id &= INT_ID_MASK;
+	}
+	else {
+		/* zero mask bits*/
+		p_common_mgid->unicast.interface_id &= (~MGID_MUX_MLID_MASK);
+	}
+}
+
+static int64_t
+__mgid_cmp(
+	IN		const	void* const					p_gid1,
+	IN		const	void* const					p_gid2 )
+{
+	return memcmp( p_gid1, p_gid2, sizeof(ib_gid_t) );
+}
+
+static osm_mgrp_port_t *osm_mgrp_port_new(ib_net64_t port_guid)
+{
+	osm_mgrp_port_t *p_mgrp_port = (osm_mgrp_port_t*)malloc(sizeof(osm_mgrp_port_t));
+	if (!p_mgrp_port) {
+		return NULL;
+	}
+	memset(p_mgrp_port, 0, sizeof(*p_mgrp_port));
+	p_mgrp_port->port_guid = port_guid;
+	cl_qlist_init(&p_mgrp_port->mgroups);
+	return p_mgrp_port;
+}
+
+void osm_mgrp_holder_delete(IN osm_subn_t * p_subn, ib_net16_t mlid)
+{
+	osm_mgrp_port_t *p_osm_mgr_port;
+	cl_map_item_t	*p_item;
+	cl_fmap_item_t  *p_fitem;
+	osm_mgrp_t * p_mgrp;
+
+	osm_mgrp_holder_t *p_mgrp_holder = 
+		p_subn->mgroup_holders[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO];
+	p_item = cl_qmap_head( &p_mgrp_holder->mgrp_port_map);
+	while (p_item != cl_qmap_end( &p_mgrp_holder->mgrp_port_map)) {
+		p_osm_mgr_port = (osm_mgrp_port_t *)p_item;
+		cl_qlist_remove_all(&p_osm_mgr_port->mgroups);
+		cl_qmap_remove_item( &p_mgrp_holder->mgrp_port_map, p_item);
+		p_item = cl_qmap_head( &p_mgrp_holder->mgrp_port_map);
+		free(p_osm_mgr_port);
+	}
+	p_fitem = cl_fmap_head( &p_mgrp_holder->mgrp_map);
+	while (p_fitem != cl_fmap_end( &p_mgrp_holder->mgrp_map)) {
+		p_mgrp = (osm_mgrp_t *)p_fitem;
+		osm_mgrp_delete(p_subn, p_mgrp);
+		p_fitem = cl_fmap_head( &p_mgrp_holder->mgrp_map);
+	}
+	/* destroy the mtree_node structure */
+	osm_mtree_destroy(p_mgrp_holder->p_root);
+	p_subn->mgroup_holders[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = NULL;
+	free(p_mgrp_holder);
+}
+
+/**********************************************************************
+ **********************************************************************/
+osm_mgrp_holder_t	*osm_mgrp_holder_new(IN osm_subn_t *p_subn,ib_gid_t * p_mgid, ib_net16_t mlid)
+{
+	osm_mgrp_holder_t *p_mgrp_holder;
+	p_mgrp_holder = p_subn->mgroup_holders[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = 
+		(osm_mgrp_holder_t *)  malloc(sizeof(*p_mgrp_holder));
+	if (!p_mgrp_holder) 
+		return NULL;
+
+	memset(p_mgrp_holder, 0, sizeof(*p_mgrp_holder));
+	p_mgrp_holder->mlid = mlid;
+	cl_fmap_init(&p_mgrp_holder->mgrp_map, __mgid_cmp);
+	cl_qmap_init(&p_mgrp_holder->mgrp_port_map);
+	osm_mgrp_holder_prepare_common_mgid(p_mgid, &p_mgrp_holder->common_mgid);
+	return p_mgrp_holder;
+}
+
+ib_net16_t osm_mgrp_holder_get_mlid_by_mgid(IN osm_sa_t * sa, IN const ib_gid_t *const p_mgid)
+{
+	int i;
+	ib_gid_t common_mgid;
+	osm_mgrp_holder_t * p_mgrp_holder;
+
+	OSM_LOG_ENTER(sa->p_log);
+
+	osm_mgrp_holder_prepare_common_mgid(p_mgid, &common_mgid);
+	for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO;
+	     i++) {
+			if (sa->p_subn->mgroup_holders[i]) {
+				p_mgrp_holder  = (osm_mgrp_holder_t*)sa->p_subn->mgroup_holders[i];
+				if ( !memcmp(&p_mgrp_holder->common_mgid, &common_mgid,sizeof(ib_gid_t))) {
+					char gid_str[INET6_ADDRSTRLEN];
+					OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
+							"Found holder  0x%X for MGID %s\n",
+							 cl_ntoh16(p_mgrp_holder->mlid),
+							 inet_ntop(AF_INET6, p_mgid->raw, gid_str,
+							 sizeof (gid_str)));
+					OSM_LOG_EXIT(sa->p_log);
+					return p_mgrp_holder->mlid;
+				}
+			}
+	}
+	OSM_LOG_EXIT(sa->p_log);
+	return 0;
+}
+
+/* drop the port */
+void osm_mgrp_holder_remove_port(osm_subn_t * subn, osm_log_t * p_log, osm_mgrp_holder_t * p_mgrp_holder,
+			  ib_net64_t port_guid)
+{
+	osm_mgrp_t * p_mgrp;
+	cl_list_item_t *p_item;
+
+	OSM_LOG_ENTER(p_log);
+
+	osm_mgrp_port_t *p_mgrp_port = (osm_mgrp_port_t*)
+	cl_qmap_remove(&p_mgrp_holder->mgrp_port_map, port_guid);			
+	if (p_mgrp_port !=  (osm_mgrp_port_t*)cl_qmap_end(&p_mgrp_holder->mgrp_port_map)) {
+			char gid_str[INET6_ADDRSTRLEN];
+			OSM_LOG(p_log, OSM_LOG_DEBUG,"port  0x%" PRIx64 " removed from  mlid 0x%X\n",
+							port_guid,cl_ntoh16(p_mgrp_holder->mlid));
+			while ((p_item = cl_qlist_remove_head(&p_mgrp_port->mgroups)) != 
+						   cl_qlist_end(&p_mgrp_port->mgroups)) {
+				p_mgrp = (osm_mgrp_t*) PARENT_STRUCT(p_item, osm_mgrp_t, mgrp_item);
+				OSM_LOG(p_log, OSM_LOG_DEBUG,"removing mgrp mgid %s from port  0x%" PRIx64 "\n",
+						inet_ntop(AF_INET6, p_mgrp->mcmember_rec.mgid.raw, gid_str, sizeof (gid_str)),
+						cl_ntoh64(port_guid));
+				osm_mgrp_delete_port(subn, p_log, p_mgrp, port_guid);
+			}
+			free(p_mgrp_port);
+	}
+	OSM_LOG_EXIT(p_log);
+}
+
+
+void osm_mgrp_holder_add_mgrp(osm_mgrp_holder_t * p_mgrp_holder, osm_mgrp_t *p_mgrp,osm_log_t * p_log)
+{
+	cl_fmap_item_t *p_fitem;
+	char gid_str[INET6_ADDRSTRLEN];
+
+	OSM_LOG_ENTER(p_log);
+
+	if (p_mgrp_holder->to_be_deleted) {
+		/* this is re-used mgrp_holder, need to update common_mgid*/
+		osm_mgrp_holder_prepare_common_mgid(&p_mgrp->mcmember_rec.mgid, 
+											&p_mgrp_holder->common_mgid);
+	}
+	p_fitem = cl_fmap_insert(&p_mgrp_holder->mgrp_map, 
+							 &p_mgrp->mcmember_rec.mgid ,&p_mgrp->mgid_item);
+    CL_ASSERT( p_item == &p_mgrp->mgid_item );
+		
+	OSM_LOG(p_log, OSM_LOG_DEBUG, "mgrp with MGID:%s added to holder with mlid = 0x%X\n",
+				inet_ntop(AF_INET6, p_mgrp->mcmember_rec.mgid.raw, gid_str,
+			   sizeof( gid_str)),cl_ntoh16(p_mgrp_holder->mlid));
+
+	p_mgrp_holder->last_change_id++;
+	OSM_LOG_EXIT(p_log);
+}
+
+ib_api_status_t osm_mgrp_holder_add_mgrp_port(osm_mgrp_holder_t *p_mgrp_holder, osm_mgrp_t *p_mgrp,
+				ib_net64_t port_guid)
+{
+	osm_mgrp_port_t *p_mgrp_port = (osm_mgrp_port_t*)
+		cl_qmap_get(&p_mgrp_holder->mgrp_port_map, port_guid);
+	if (p_mgrp_port == (osm_mgrp_port_t*)cl_qmap_end(&p_mgrp_holder->mgrp_port_map)) {
+		/* new port to mlid*/
+		p_mgrp_port = osm_mgrp_port_new(port_guid);
+		if (!p_mgrp_port) {
+			return IB_INSUFFICIENT_MEMORY;
+		}
+		cl_qmap_insert(&p_mgrp_holder->mgrp_port_map, 
+					   p_mgrp_port->port_guid, 
+					   &p_mgrp_port->guid_item);
+		cl_qlist_insert_tail(&p_mgrp_port->mgroups, 
+					   &p_mgrp->mgrp_item);
+	}
+	else {
+		cl_qlist_insert_tail(&p_mgrp_port->mgroups, &p_mgrp->mgrp_item);
+	}
+	return IB_SUCCESS;
+}
+
+void osm_mgrp_holder_delete_mgrp_port(osm_mgrp_holder_t *p_mgrp_holder,  osm_mgrp_t *p_mgrp, 
+				ib_net64_t port_guid)
+{
+	osm_mgrp_port_t *p_mgrp_port = (osm_mgrp_port_t*)
+		cl_qmap_get(&p_mgrp_holder->mgrp_port_map, port_guid);
+	if (p_mgrp_port != (osm_mgrp_port_t*)cl_qmap_end(&p_mgrp_holder->mgrp_port_map)) {
+		cl_qlist_remove_item(&p_mgrp_port->mgroups, &p_mgrp->mgrp_item);
+		if (0 == cl_qlist_count(&p_mgrp_port->mgroups)) {
+			/* No mgroups registered on this port for current mlid*/
+			cl_qmap_remove_item(&p_mgrp_holder->mgrp_port_map, &p_mgrp_port->guid_item);
+			free(p_mgrp_port);
+		}
+		p_mgrp_holder->last_change_id++;
+	}
+}
+
+void osm_mgrp_holder_delete_mgrp(osm_mgrp_holder_t *p_mgrp_holder,  osm_mgrp_t *p_mgrp)
+{
+	p_mgrp->to_be_deleted = 1;
+	cl_fmap_remove_item(&p_mgrp_holder->mgrp_map, &p_mgrp->mgid_item);
+	if (0 == cl_fmap_count(&p_mgrp_holder->mgrp_map)) {
+		/* No more mgroups on this mlid*/
+		p_mgrp_holder->to_be_deleted = 1;
+		p_mgrp_holder->last_tree_id = 0;
+		p_mgrp_holder->last_change_id = 0;
+		memset(&p_mgrp_holder->common_mgid,0,sizeof(ib_gid_t));
+	}
+}
+/**********************************************************************
+ **********************************************************************/
+
diff --git a/opensm/opensm/osm_multicast.c b/opensm/opensm/osm_multicast.c
index d2733c4..f57b3e9 100644
--- a/opensm/opensm/osm_multicast.c
+++ b/opensm/opensm/osm_multicast.c
@@ -41,23 +41,24 @@
 #if HAVE_CONFIG_H
 #  include <config.h>
 #endif				/* HAVE_CONFIG_H */
-
+#include <arpa/inet.h>
 #include <stdlib.h>
 #include <string.h>
 #include <opensm/osm_multicast.h>
 #include <opensm/osm_mcm_port.h>
 #include <opensm/osm_mtree.h>
 #include <opensm/osm_inform.h>
-
+#include <opensm/osm_mgrp_holder.h>
 /**********************************************************************
  **********************************************************************/
-void osm_mgrp_delete(IN osm_mgrp_t * p_mgrp)
+void osm_mgrp_delete(IN osm_subn_t * p_subn, IN osm_mgrp_t *p_mgrp)
 {
 	osm_mcm_port_t *p_mcm_port;
 	osm_mcm_port_t *p_next_mcm_port;
 
 	CL_ASSERT(p_mgrp);
 
+	osm_mgrp_holder_t *p_mgrp_holder = osm_get_mgrp_holder_by_mlid(p_subn, p_mgrp->mlid);
 	p_next_mcm_port =
 	    (osm_mcm_port_t *) cl_qmap_head(&p_mgrp->mcm_port_tbl);
 	while (p_next_mcm_port !=
@@ -65,14 +66,13 @@ void osm_mgrp_delete(IN osm_mgrp_t * p_mgrp)
 		p_mcm_port = p_next_mcm_port;
 		p_next_mcm_port =
 		    (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item);
+		osm_mgrp_holder_delete_mgrp_port(p_mgrp_holder, p_mgrp, 
+						 p_mcm_port->port_gid.unicast.interface_id);
 		osm_mcm_port_delete(p_mcm_port);
 	}
-	/* destroy the mtree_node structure */
-	osm_mtree_destroy(p_mgrp->p_root);
-
+	osm_mgrp_holder_delete_mgrp(p_mgrp_holder, p_mgrp);
 	free(p_mgrp);
 }
-
 /**********************************************************************
  **********************************************************************/
 osm_mgrp_t *osm_mgrp_new(IN const ib_net16_t mlid)
@@ -133,6 +133,7 @@ osm_mcm_port_t *osm_mgrp_add_port(IN osm_subn_t * subn, osm_log_t * log,
 	ib_net64_t port_guid;
 	osm_mcm_port_t *p_mcm_port;
 	cl_map_item_t *prev_item;
+	osm_mgrp_holder_t *p_mgrp_holder;
 	uint8_t prev_join_state = 0;
 	uint8_t prev_scope;
 
@@ -168,8 +169,25 @@ osm_mcm_port_t *osm_mgrp_add_port(IN osm_subn_t * subn, osm_log_t * log,
 		    ib_member_set_scope_state(prev_scope,
 					      prev_join_state | join_state);
 	} else {
-		/* track the fact we modified the group ports */
-		p_mgrp->last_change_id++;
+		p_mgrp_holder = subn->mgroup_holders[cl_ntoh16(p_mgrp->mlid) - IB_LID_MCAST_START_HO];
+		if (!p_mgrp_holder) 
+			/* create new holder */
+			p_mgrp_holder = 
+			subn->mgroup_holders[cl_ntoh16(p_mgrp->mlid) - IB_LID_MCAST_START_HO] = 
+			osm_mgrp_holder_new(subn,&p_mgrp->mcmember_rec.mgid,p_mgrp->mlid);
+	
+		if (p_mgrp_holder &&
+			 (IB_SUCCESS == osm_mgrp_holder_add_mgrp_port(p_mgrp_holder,
+						p_mgrp, port_guid)) ) {
+			/* track the fact we modified the group ports */
+			p_mgrp->last_change_id++;
+		}
+		else {
+			/*  if  osm_mgrp_holder_new failed, remove port also from mcm_port_tbl */
+			cl_qmap_remove_item(&p_mgrp->mcm_port_tbl, &p_mcm_port->map_item);
+			osm_mcm_port_delete(p_mcm_port);
+			return NULL;
+		}
 	}
 
 	if ((join_state & IB_JOIN_STATE_FULL) &&
@@ -190,7 +208,7 @@ int osm_mgrp_remove_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp,
 	int ret;
 	uint8_t port_join_state;
 	uint8_t new_join_state;
-
+	char gid_str[INET6_ADDRSTRLEN];
 	/*
 	 * according to the same o15-0.1.14 we get the stored
 	 * JoinState and the request JoinState and they must be
@@ -198,7 +216,9 @@ int osm_mgrp_remove_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp,
 	 */
 	port_join_state = mcm->scope_state & 0x0F;
 	new_join_state = port_join_state & ~join_state;
-
+	OSM_LOG(log, OSM_LOG_DEBUG, "mgrp mgid %s well_known = %d, new_join_state = %d\n",
+			inet_ntop(AF_INET6, mgrp->mcmember_rec.mgid.raw, gid_str, sizeof( gid_str)),
+			mgrp->well_known,new_join_state);
 	if (new_join_state) {
 		mcm->scope_state = new_join_state | (mcm->scope_state & 0xf0);
 		OSM_LOG(log, OSM_LOG_DEBUG,
@@ -283,18 +303,3 @@ static void mgrp_apply_func_sub(const osm_mgrp_t * p_mgrp,
 	}
 }
 
-/**********************************************************************
- **********************************************************************/
-void osm_mgrp_apply_func(const osm_mgrp_t * p_mgrp, osm_mgrp_func_t p_func,
-			 void *context)
-{
-	osm_mtree_node_t *p_mtn;
-
-	CL_ASSERT(p_mgrp);
-	CL_ASSERT(p_func);
-
-	p_mtn = p_mgrp->p_root;
-
-	if (p_mtn)
-		mgrp_apply_func_sub(p_mgrp, p_mtn, p_func, context);
-}
diff --git a/opensm/opensm/osm_qos_policy.c b/opensm/opensm/osm_qos_policy.c
index 094fef2..1d15776 100644
--- a/opensm/opensm/osm_qos_policy.c
+++ b/opensm/opensm/osm_qos_policy.c
@@ -53,6 +53,7 @@
 #include <opensm/osm_partition.h>
 #include <opensm/osm_opensm.h>
 #include <opensm/osm_qos_policy.h>
+#include <opensm/osm_mgrp_holder.h>
 
 extern osm_qos_level_t __default_simple_qos_level;
 
@@ -796,6 +797,8 @@ static void __qos_policy_validate_pkey(
 	uint32_t flow;
 	uint8_t hop;
 	osm_mgrp_t * p_mgrp;
+	osm_mgrp_holder_t *p_mgrp_holder;
+	cl_fmap_item_t *p_fitem;
 
 	if (!p_qos_policy || !p_qos_match_rule || !p_prtn)
 		return;
@@ -819,28 +822,33 @@ static void __qos_policy_validate_pkey(
 	if (!p_prtn->mlid)
 		return;
 
-	p_mgrp = osm_get_mgrp_by_mlid(p_qos_policy->p_subn, p_prtn->mlid);
-	if (!p_mgrp) {
+	p_mgrp_holder = osm_get_mgrp_holder_by_mlid(p_qos_policy->p_subn, p_prtn->mlid);
+	if (!p_mgrp_holder) {
 		OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_ERROR,
-			"ERR AC16: MCast group for partition with "
+			"ERR AC16: MCast mgrp_holder for partition with "
 			"pkey 0x%04X not found\n",
 			cl_ntoh16(p_prtn->pkey));
 		return;
 	}
-
-	CL_ASSERT((cl_ntoh16(p_mgrp->mcmember_rec.pkey) & 0x7fff) ==
-		  (cl_ntoh16(p_prtn->pkey) & 0x7fff));
-
-	ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
-				  &sl, &flow, &hop);
-	if (sl != p_prtn->sl) {
-		OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_DEBUG,
-			"Updating MCGroup (MLID 0x%04x) SL to "
-			"match partition SL (%u)\n",
-			cl_hton16(p_mgrp->mcmember_rec.mlid),
-			p_prtn->sl);
-		p_mgrp->mcmember_rec.sl_flow_hop =
-			ib_member_set_sl_flow_hop(p_prtn->sl, flow, hop);
+	p_fitem = cl_fmap_head(&p_mgrp_holder->mgrp_map);
+	while (p_fitem != cl_fmap_end(&p_mgrp_holder->mgrp_map)) {
+		p_mgrp = (osm_mgrp_t*)p_fitem;
+		p_fitem = cl_fmap_next(p_fitem);
+	
+		CL_ASSERT((cl_ntoh16(p_mgrp->mcmember_rec.pkey) & 0x7fff) ==
+			  (cl_ntoh16(p_prtn->pkey) & 0x7fff));
+	
+		ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
+					  &sl, &flow, &hop);
+		if (sl != p_prtn->sl) {
+			OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_DEBUG,
+				"Updating MCGroup (MLID 0x%04x) SL to "
+				"match partition SL (%u)\n",
+				cl_hton16(p_mgrp->mcmember_rec.mlid),
+				p_prtn->sl);
+			p_mgrp->mcmember_rec.sl_flow_hop =
+				ib_member_set_sl_flow_hop(p_prtn->sl, flow, hop);
+		}
 	}
 }
 
diff --git a/opensm/opensm/osm_sa.c b/opensm/opensm/osm_sa.c
index 3521132..e32f5c5 100644
--- a/opensm/opensm/osm_sa.c
+++ b/opensm/opensm/osm_sa.c
@@ -52,6 +52,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <complib/cl_qmap.h>
+#include <complib/cl_fleximap.h>
 #include <complib/cl_passivelock.h>
 #include <complib/cl_debug.h>
 #include <iba/ib_types.h>
@@ -67,6 +68,7 @@
 #include <opensm/osm_service.h>
 #include <opensm/osm_helper.h>
 #include <vendor/osm_vendor_api.h>
+#include <opensm/osm_mgrp_holder.h>
 
 #define  OSM_SA_INITIAL_TID_VALUE 0xabc
 
@@ -705,6 +707,7 @@ static void sa_dump_all_sa(osm_opensm_t * p_osm, FILE * file)
 {
 	struct opensm_dump_context dump_context;
 	osm_mgrp_t *p_mgrp;
+	osm_mgrp_holder_t * p_mgrp_holder;
 	int i;
 
 	dump_context.p_osm = p_osm;
@@ -713,9 +716,14 @@ static void sa_dump_all_sa(osm_opensm_t * p_osm, FILE * file)
 	cl_plock_acquire(&p_osm->lock);
 	for (i = 0; i <= p_osm->subn.max_mcast_lid_ho - IB_LID_MCAST_START_HO;
 	     i++) {
-		p_mgrp = p_osm->subn.mgroups[i];
-		if (p_mgrp)
+		p_mgrp_holder = p_osm->subn.mgroup_holders[i];
+		if (!p_mgrp_holder)
+			continue;
+		p_mgrp = (osm_mgrp_t*)cl_fmap_head(&p_mgrp_holder->mgrp_map);
+		while (p_mgrp != (osm_mgrp_t*)cl_fmap_end(&p_mgrp_holder->mgrp_map)) {
 			sa_dump_one_mgrp(p_mgrp, &dump_context);
+			p_mgrp = (osm_mgrp_t*)cl_fmap_next(&p_mgrp->mgid_item);
+		}
 	}
 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump inform\n");
 	cl_qlist_apply_func(&p_osm->subn.sa_infr_list,
@@ -740,24 +748,28 @@ static osm_mgrp_t *load_mcgroup(osm_opensm_t * p_osm, ib_net16_t mlid,
 {
 	ib_net64_t comp_mask;
 	osm_mgrp_t *p_mgrp;
-
+	osm_mgrp_holder_t *p_mgrp_holder;
+	ib_gid_t  common_mgid;
 	cl_plock_excl_acquire(&p_osm->lock);
 
-	p_mgrp = osm_get_mgrp_by_mlid(&p_osm->subn, mlid);
-	if (p_mgrp) {
-		if (!memcmp(&p_mgrp->mcmember_rec.mgid, &p_mcm_rec->mgid,
-			    sizeof(ib_gid_t))) {
+	p_mgrp_holder = osm_get_mgrp_holder_by_mlid(&p_osm->subn, mlid);
+	if (p_mgrp_holder) {
+		p_mgrp = (osm_mgrp_t*)cl_fmap_get(&p_mgrp_holder->mgrp_map ,&p_mcm_rec->mgid);
+		if (p_mgrp != (osm_mgrp_t*)cl_fmap_end(&p_mgrp_holder->mgrp_map)) {
 			OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
 				"mgrp %04x is already here.", cl_ntoh16(mlid));
 			goto _out;
 		}
-		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
-			"mlid %04x is already used by another MC group. Will "
-			"request clients reregistration.\n", cl_ntoh16(mlid));
-		p_mgrp = NULL;
-		goto _out;
-	}
 
+		osm_mgrp_holder_prepare_common_mgid(&p_mcm_rec->mgid, &common_mgid);
+		if (memcmp(&p_mgrp_holder->common_mgid, &common_mgid, sizeof(ib_gid_t))) {
+			OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
+				"mlid %04x is already used by another MC group. Will "
+				"request clients reregistration.\n", cl_ntoh16(mlid));
+			p_mgrp = NULL;
+			goto _out;
+		}
+    }
 	comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL
 	    | IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL;
 	if (osm_mcmr_rcv_find_or_create_new_mgrp(&p_osm->sa,
diff --git a/opensm/opensm/osm_sa_mcmember_record.c b/opensm/opensm/osm_sa_mcmember_record.c
index 5543221..d431cfb 100644
--- a/opensm/opensm/osm_sa_mcmember_record.c
+++ b/opensm/opensm/osm_sa_mcmember_record.c
@@ -63,6 +63,7 @@
 #include <opensm/osm_pkey.h>
 #include <opensm/osm_inform.h>
 #include <opensm/osm_sa.h>
+#include <opensm/osm_mgrp_holder.h>
 
 #define JOIN_MC_COMP_MASK (IB_MCR_COMPMASK_MGID | \
 				IB_MCR_COMPMASK_PORT_GID | \
@@ -121,13 +122,13 @@ static ib_net16_t get_new_mlid(osm_sa_t * sa, ib_net16_t requested_mlid)
 
 	if (requested_mlid && cl_ntoh16(requested_mlid) >= IB_LID_MCAST_START_HO
 	    && cl_ntoh16(requested_mlid) <= p_subn->max_mcast_lid_ho
-	    && !osm_get_mgrp_by_mlid(p_subn, requested_mlid))
+	    && !osm_get_mgrp_holder_by_mlid(p_subn, requested_mlid))
 		return requested_mlid;
 
 	max = p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO + 1;
 	for (i = 0; i < max; i++) {
-		osm_mgrp_t *p_mgrp = sa->p_subn->mgroups[i];
-		if (!p_mgrp || p_mgrp->to_be_deleted)
+		osm_mgrp_holder_t *p_mgrp_holder = (osm_mgrp_holder_t*)sa->p_subn->mgroup_holders[i];
+		if (!p_mgrp_holder || p_mgrp_holder->to_be_deleted)
 			return cl_hton16(i + IB_LID_MCAST_START_HO);
 	}
 
@@ -141,14 +142,16 @@ static ib_net16_t get_new_mlid(osm_sa_t * sa, ib_net16_t requested_mlid)
  we silently drop it. Since it was an intermediate group no need to
  re-route it.
 **********************************************************************/
-static void cleanup_mgrp(IN osm_sa_t * sa, osm_mgrp_t * mgrp)
+static void cleanup_mgrp(IN osm_sa_t * sa, osm_mgrp_t * p_mgrp)
 {
 	/* Remove MGRP only if osm_mcm_port_t count is 0 and
 	   not a well known group */
-	if (cl_is_qmap_empty(&mgrp->mcm_port_tbl) && !mgrp->well_known) {
-		sa->p_subn->mgroups[cl_ntoh16(mgrp->mlid) -
-				    IB_LID_MCAST_START_HO] = NULL;
-		osm_mgrp_delete(mgrp);
+	char gid_str[INET6_ADDRSTRLEN];
+	if (cl_is_qmap_empty(&p_mgrp->mcm_port_tbl) && !p_mgrp->well_known) {
+		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,"mgrp mgid %s will be deleted\n",
+		        inet_ntop(AF_INET6, p_mgrp->mcmember_rec.mgid.raw, 
+			gid_str, sizeof( gid_str)));
+		osm_mgrp_delete(sa->sm->p_subn,p_mgrp);
 	}
 }
 
@@ -202,7 +205,6 @@ static ib_api_status_t add_new_mgrp_port(osm_sa_t * sa, IN osm_mgrp_t * p_mgrp,
 
 		return IB_INSUFFICIENT_MEMORY;
 	}
-
 	return IB_SUCCESS;
 }
 
@@ -806,11 +808,12 @@ ib_api_status_t osm_mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa,
 					     IN const osm_physp_t * p_physp,
 					     OUT osm_mgrp_t ** pp_mgrp)
 {
-	ib_net16_t mlid;
+	ib_net16_t mlid, existed_mlid;
 	unsigned zero_mgid, i;
 	uint8_t scope;
+	char gid_str[INET6_ADDRSTRLEN];
 	ib_gid_t *p_mgid;
-	osm_mgrp_t *p_prev_mgrp;
+	osm_mgrp_holder_t	*p_mgrp_holder;
 	ib_api_status_t status = IB_SUCCESS;
 	ib_member_rec_t mcm_rec = *p_recvd_mcmember_rec;	/* copy for modifications */
 
@@ -823,11 +826,11 @@ ib_api_status_t osm_mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa,
 			zero_mgid = 0;
 			break;
 		}
-
+	p_mgid = &(mcm_rec.mgid);
 	/*
 	   we allocate a new mlid number before we might use it
 	   for MGID ...
-	 */
+	*/
 	mlid = get_new_mlid(sa, mcm_rec.mlid);
 	if (mlid == 0) {
 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B19: "
@@ -843,8 +846,6 @@ ib_api_status_t osm_mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa,
 	/* we need to create the new MGID if it was not defined */
 	if (zero_mgid) {
 		/* create a new MGID */
-		char gid_str[INET6_ADDRSTRLEN];
-
 		/* use the given scope state only if requested! */
 		if (comp_mask & IB_MCR_COMPMASK_SCOPE)
 			ib_member_get_scope_state(p_recvd_mcmember_rec->
@@ -888,6 +889,12 @@ ib_api_status_t osm_mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa,
 		goto Exit;
 	}
 
+	if (0 != (existed_mlid = osm_mgrp_holder_get_mlid_by_mgid(sa,p_mgid))) {
+		mlid = existed_mlid;
+		OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 
+			"found existed  mlid  0x%04x for mgid %s\n",
+			cl_ntoh16(mlid),inet_ntop(AF_INET6, p_mgid->raw, gid_str,sizeof gid_str));
+	}
 	/* create a new MC Group */
 	*pp_mgrp = osm_mgrp_new(mlid);
 	if (*pp_mgrp == NULL) {
@@ -915,17 +922,20 @@ ib_api_status_t osm_mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa,
 	/* since we might have an old group by that mlid
 	   one whose deletion was delayed for an idle time
 	   we need to deallocate it first */
-	p_prev_mgrp = osm_get_mgrp_by_mlid(sa->p_subn, mlid);
-	if (p_prev_mgrp) {
+	p_mgrp_holder = osm_get_mgrp_holder_by_mlid(sa->p_subn, mlid);
+	if (! p_mgrp_holder) {
 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
-			"Found previous group for mlid:0x%04x - "
-			"Destroying it first\n", cl_ntoh16(mlid));
-		sa->p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] =
-		    NULL;
-		osm_mgrp_delete(p_prev_mgrp);
+			"Creating new mgrp holder  for mlid:0x%04x\n", cl_ntoh16(mlid));
+		p_mgrp_holder = osm_mgrp_holder_new(sa->p_subn,p_mgid, mlid);
 	}
-
-	sa->p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = *pp_mgrp;
+	if (!p_mgrp_holder) {
+		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B08: "
+			"osm_mgrp_holder_new failed\n");
+		free_mlid(sa, mlid);
+		status = IB_INSUFFICIENT_MEMORY;
+		goto Exit;
+	}
+	osm_mgrp_holder_add_mgrp(p_mgrp_holder, *pp_mgrp, sa->p_log);
 
 Exit:
 	OSM_LOG_EXIT(sa->p_log);
@@ -934,56 +944,42 @@ Exit:
 
 /**********************************************************************
  *********************************************************************/
-static unsigned match_mgrp_by_mgid(IN osm_mgrp_t * p_mgrp, ib_gid_t * mgid)
-{
-	/* ignore groups marked for deletion */
-	if (p_mgrp->to_be_deleted ||
-	    memcmp(&p_mgrp->mcmember_rec.mgid, mgid, sizeof(ib_gid_t)))
-		return 0;
-	else
-		return 1;
-}
-
-/**********************************************************************
- **********************************************************************/
-#define PREFIX_MASK CL_HTON64(0xff10ffff0000ffffULL)
-#define PREFIX_SIGNATURE CL_HTON64(0xff10601b00000000ULL)
-#define INT_ID_MASK CL_HTON64(0xfffffff1ff000000ULL)
-#define INT_ID_SIGNATURE CL_HTON64(0x00000001ff000000ULL)
-
-/* Special Case IPv6 Solicited Node Multicast (SNM) addresses */
-/* 0xff1Z601bXXXX0000 : 0x00000001ffYYYYYY */
-/* Where Z is the scope, XXXX is the P_Key, and
- * YYYYYY is the last 24 bits of the port guid */
-static unsigned match_and_update_ipv6_snm_mgid(ib_gid_t * mgid)
+static osm_mgrp_t*  match_mgrp_by_mgid(IN osm_mgrp_holder_t * p_mgrp_holder, ib_gid_t * p_mgid)
 {
-	if ((mgid->unicast.prefix & PREFIX_MASK) == PREFIX_SIGNATURE &&
-	    (mgid->unicast.interface_id & INT_ID_MASK) == INT_ID_SIGNATURE) {
-		mgid->unicast.prefix &= PREFIX_MASK;
-		mgid->unicast.interface_id &= INT_ID_MASK;
-		return 1;
+	osm_mgrp_t	*p_mgrp;
+	ib_gid_t  common_mgid;
+
+	osm_mgrp_holder_prepare_common_mgid(p_mgid, &common_mgid);
+	
+	if (memcmp(&p_mgrp_holder->common_mgid, &common_mgid, sizeof(ib_gid_t)))
+		return NULL;
+	p_mgrp = (osm_mgrp_t*)cl_fmap_get(&p_mgrp_holder->mgrp_map,p_mgid);
+	if (p_mgrp != (osm_mgrp_t*)cl_fmap_end(&p_mgrp_holder->mgrp_map)) {
+		/* ignore groups marked for deletion */
+		if (p_mgrp->to_be_deleted) 
+			p_mgrp = NULL;
 	}
-	return 0;
+	else
+		p_mgrp = NULL;
+	return p_mgrp;;
 }
 
 osm_mgrp_t *osm_get_mgrp_by_mgid(IN osm_sa_t * sa, IN ib_gid_t * p_mgid)
 {
 	int i;
-
-	if (sa->p_subn->opt.consolidate_ipv6_snm_req &&
-	    match_and_update_ipv6_snm_mgid(p_mgid)) {
-		char gid_str[INET6_ADDRSTRLEN];
-		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
-			"Special Case Solicited Node Mcast Join for MGID %s\n",
-			inet_ntop(AF_INET6, p_mgid->raw, gid_str,
-				  sizeof gid_str));
-	}
-
+	osm_mgrp_t *p_mgrp;
 	for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO;
-	     i++)
-		if (sa->p_subn->mgroups[i] &&
-		    match_mgrp_by_mgid(sa->p_subn->mgroups[i], p_mgid))
-			return sa->p_subn->mgroups[i];
+	     i++) {
+			if (sa->p_subn->mgroup_holders[i] &&
+				(p_mgrp = match_mgrp_by_mgid(sa->p_subn->mgroup_holders[i], p_mgid))) {
+					char gid_str[INET6_ADDRSTRLEN];
+					OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
+							"Found mgroup for MGID %s\n",
+							 inet_ntop(AF_INET6, p_mgid->raw, gid_str,
+							 sizeof gid_str));
+					return p_mgrp;
+			}
+	}
 
 	return NULL;
 }
@@ -1080,7 +1076,7 @@ static void mcmr_rcv_leave_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
 	CL_PLOCK_RELEASE(sa->p_lock);
 
 	/* we can leave if port was deleted from MCG */
-	if (removed && osm_sm_mcgrp_leave(sa->sm, mlid, portguid))
+	if (removed && osm_sm_mcgrp_leave(sa->sm, p_mgrp, portguid))
 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B09: "
 			"osm_sm_mcgrp_leave failed\n");
 
@@ -1309,8 +1305,8 @@ static void mcmr_rcv_join_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
 
 	/* do the actual routing (actually schedule the update) */
 	status = osm_sm_mcgrp_join(sa->sm, mlid,
-				   p_recvd_mcmember_rec->port_gid.unicast.
-				   interface_id);
+				   p_recvd_mcmember_rec->port_gid.unicast.interface_id,
+				   &p_recvd_mcmember_rec->mgid);
 
 	if (status != IB_SUCCESS) {
 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B14: "
@@ -1555,6 +1551,7 @@ static void mcmr_query_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
 	osm_physp_t *p_req_physp;
 	boolean_t trusted_req;
 	osm_mgrp_t *p_mgrp;
+	osm_mgrp_holder_t * p_mgrp_holder;
 	int i;
 
 	OSM_LOG_ENTER(sa->p_log);
@@ -1586,10 +1583,15 @@ static void mcmr_query_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
 	/* simply go over all MCGs and match */
 	for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO;
 	     i++) {
-		p_mgrp = sa->p_subn->mgroups[i];
-		if (p_mgrp)
+		p_mgrp_holder = sa->p_subn->mgroup_holders[i];
+		if (!p_mgrp_holder)
+			continue;
+		p_mgrp = (osm_mgrp_t*)cl_fmap_head(&p_mgrp_holder->mgrp_map);
+		while (p_mgrp != (osm_mgrp_t*)cl_fmap_end(&p_mgrp_holder->mgrp_map)) {
 			mcmr_by_comp_mask(sa, p_rcvd_rec, comp_mask, p_mgrp,
 					  p_req_physp, trusted_req, &rec_list);
+			p_mgrp = (osm_mgrp_t*)cl_fmap_next(&p_mgrp->mgid_item);
+		}
 	}
 
 	CL_PLOCK_RELEASE(sa->p_lock);
diff --git a/opensm/opensm/osm_sa_path_record.c b/opensm/opensm/osm_sa_path_record.c
index 9b50deb..e1e324f 100644
--- a/opensm/opensm/osm_sa_path_record.c
+++ b/opensm/opensm/osm_sa_path_record.c
@@ -68,6 +68,7 @@
 #include <opensm/osm_router.h>
 #include <opensm/osm_prefix_route.h>
 #include <opensm/osm_ucast_lash.h>
+#include <opensm/osm_mgrp_holder.h>
 
 typedef struct osm_pr_item {
 	cl_list_item_t list_item;
@@ -1438,6 +1439,7 @@ static osm_mgrp_t *pr_get_mgrp(IN osm_sa_t * sa, IN const osm_madw_t * p_madw)
 	ib_path_rec_t *p_pr;
 	const ib_sa_mad_t *p_sa_mad;
 	ib_net64_t comp_mask;
+	osm_mgrp_holder_t *p_mgrp_holder;
 	osm_mgrp_t *mgrp = NULL;
 
 	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
@@ -1468,11 +1470,17 @@ static osm_mgrp_t *pr_get_mgrp(IN osm_sa_t * sa, IN const osm_madw_t * p_madw)
 				mgrp = NULL;
 				goto Exit;
 			}
-		} else
-		    if (!(mgrp = osm_get_mgrp_by_mlid(sa->p_subn, p_pr->dlid)))
-			OSM_LOG(sa->p_log, OSM_LOG_ERROR,
-				"ERR 1F11: " "No MC group found for PathRecord "
-				"destination LID 0x%x\n", p_pr->dlid);
+		} else {
+				p_mgrp_holder = osm_get_mgrp_holder_by_mlid(sa->p_subn, p_pr->dlid);
+				if (p_mgrp_holder) {
+					mgrp = (osm_mgrp_t*)cl_fmap_get(&p_mgrp_holder->mgrp_map, &p_pr->dgid);
+				}
+				if (!p_mgrp_holder || mgrp == (osm_mgrp_t*)cl_fmap_end(&p_mgrp_holder->mgrp_map)) {
+					OSM_LOG(sa->p_log, OSM_LOG_ERROR,
+							"ERR 1F11: " "No MC group found for PathRecord "
+							"destination LID 0x%x\n", p_pr->dlid);
+				}
+		}
 	}
 
 Exit:
diff --git a/opensm/opensm/osm_sm.c b/opensm/opensm/osm_sm.c
index daa60ff..5b6d8cf 100644
--- a/opensm/opensm/osm_sm.c
+++ b/opensm/opensm/osm_sm.c
@@ -47,6 +47,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <arpa/inet.h>
 #include <iba/ib_types.h>
 #include <complib/cl_qmap.h>
 #include <complib/cl_passivelock.h>
@@ -60,6 +61,7 @@
 #include <opensm/osm_mcm_info.h>
 #include <opensm/osm_perfmgr.h>
 #include <opensm/osm_opensm.h>
+#include <opensm/osm_mgrp_holder.h>
 
 #define  OSM_SM_INITIAL_TID_VALUE 0x1233
 
@@ -468,12 +470,14 @@ static ib_api_status_t sm_mgrp_process(IN osm_sm_t * p_sm,
 /**********************************************************************
  **********************************************************************/
 ib_api_status_t osm_sm_mcgrp_join(IN osm_sm_t * p_sm, IN const ib_net16_t mlid,
-				  IN const ib_net64_t port_guid)
+				  IN const ib_net64_t port_guid, IN const ib_gid_t * p_mgid)
 {
-	osm_mgrp_t *p_mgrp;
+	osm_mgrp_t *p_mgrp = NULL;
 	osm_port_t *p_port;
 	ib_api_status_t status = IB_SUCCESS;
 	osm_mcm_info_t *p_mcm;
+	cl_fmap_item_t	*p_item;
+	osm_mgrp_holder_t *p_mgrp_holder;
 
 	OSM_LOG_ENTER(p_sm->p_log);
 
@@ -498,8 +502,38 @@ ib_api_status_t osm_sm_mcgrp_join(IN osm_sm_t * p_sm, IN const ib_net16_t mlid,
 	/*
 	 * If this multicast group does not already exist, create it.
 	 */
-	p_mgrp = osm_get_mgrp_by_mlid(p_sm->p_subn, mlid);
-	if (!p_mgrp || !osm_mgrp_is_guid(p_mgrp, port_guid)) {
+	p_mgrp_holder = osm_get_mgrp_holder_by_mlid(p_sm->p_subn, mlid);
+	if (p_mgrp_holder) {
+		    char gid_str[INET6_ADDRSTRLEN];
+		    if (osm_is_debug()) {
+				size_t  gr_count = cl_fmap_count(&p_mgrp_holder->mgrp_map);
+				OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG,"mlid 0x%X has  %d mgroups\n",
+						cl_ntoh16(mlid),gr_count);
+				if (gr_count) {
+					p_mgrp = (osm_mgrp_t*)cl_fmap_head( &p_mgrp_holder->mgrp_map);
+					while (p_mgrp != (osm_mgrp_t*)cl_fmap_end( &p_mgrp_holder->mgrp_map)) {
+						OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG,
+								"mlid  0x%X has mgrp with MGID: %s\n",cl_ntoh16(mlid),
+								inet_ntop(AF_INET6,
+									  p_mgrp->mcmember_rec.mgid.raw,
+									  gid_str, sizeof gid_str));
+						p_mgrp = (osm_mgrp_t*)cl_fmap_next( &p_mgrp->mgid_item);
+					}
+				}
+			}
+			p_item = cl_fmap_get( &p_mgrp_holder->mgrp_map, p_mgid );
+			if ( p_item == cl_fmap_end( &p_mgrp_holder->mgrp_map ) ) {
+					p_mgrp = NULL;					
+					OSM_LOG(p_sm->p_log, OSM_LOG_ERROR,
+						"group with MGID: %s not found on mlid 0x%X\n",
+						inet_ntop(AF_INET6,
+							  p_mgid->raw,
+							  gid_str, sizeof gid_str), cl_ntoh16(mlid));
+					}
+			else
+				p_mgrp = (osm_mgrp_t *)p_item;
+	}
+	if (!p_mgrp_holder || !p_mgrp || !osm_mgrp_is_guid(p_mgrp, port_guid)) {
 		/*
 		 * The group removed or the port is not a
 		 * member of the group, then fail immediately.
@@ -514,7 +548,21 @@ ib_api_status_t osm_sm_mcgrp_join(IN osm_sm_t * p_sm, IN const ib_net16_t mlid,
 		status = IB_NOT_FOUND;
 		goto Exit;
 	}
-
+	/* if there was no change from the last time
+	 * we processed the group we can skip doing anything
+	 */
+	if (p_mgrp_holder->last_change_id == p_mgrp_holder->last_tree_id) {
+		CL_PLOCK_RELEASE(p_sm->p_lock);
+		OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE,
+			"Skip processing mgrp holder with lid:0x%X last change id:%u\n",
+			cl_ntoh16(mlid), p_mgrp_holder->last_change_id);
+		goto Exit;
+	} else {
+		OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG,
+			"processing mgrp holder with lid:0x%X port: 0x%016" PRIx64 " last change id:%u tree id:%u\n",
+			cl_ntoh16(mlid), cl_ntoh64(port_guid), 
+			p_mgrp_holder->last_change_id, p_mgrp_holder->last_tree_id);
+	}
 	/*
 	 * Check if the object (according to mlid) already exists on this port.
 	 * If it does - then no need to update it again, and no need to
@@ -543,9 +591,6 @@ ib_api_status_t osm_sm_mcgrp_join(IN osm_sm_t * p_sm, IN const ib_net16_t mlid,
 		goto Exit;
 	}
 
-	status = sm_mgrp_process(p_sm, p_mgrp);
-	CL_PLOCK_RELEASE(p_sm->p_lock);
-
 Exit:
 	OSM_LOG_EXIT(p_sm->p_log);
 	return status;
@@ -553,12 +598,13 @@ Exit:
 
 /**********************************************************************
  **********************************************************************/
-ib_api_status_t osm_sm_mcgrp_leave(IN osm_sm_t * p_sm, IN const ib_net16_t mlid,
+ib_api_status_t osm_sm_mcgrp_leave(IN osm_sm_t * p_sm, IN osm_mgrp_t *p_mgrp,
 				   IN const ib_net64_t port_guid)
 {
-	osm_mgrp_t *p_mgrp;
 	osm_port_t *p_port;
 	ib_api_status_t status;
+	osm_mgrp_holder_t *p_mgrp_holder;
+	ib_net16_t mlid = p_mgrp->mlid;
 
 	OSM_LOG_ENTER(p_sm->p_log);
 
@@ -584,8 +630,8 @@ ib_api_status_t osm_sm_mcgrp_leave(IN osm_sm_t * p_sm, IN const ib_net16_t mlid,
 	/*
 	 * Get the multicast group object for this group.
 	 */
-	p_mgrp = osm_get_mgrp_by_mlid(p_sm->p_subn, mlid);
-	if (!p_mgrp) {
+	p_mgrp_holder = osm_get_mgrp_holder_by_mlid(p_sm->p_subn, mlid);
+	if (!p_mgrp_holder) {
 		CL_PLOCK_RELEASE(p_sm->p_lock);
 		OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E08: "
 			"No multicast group for MLID 0x%X\n", cl_ntoh16(mlid));
@@ -593,11 +639,12 @@ ib_api_status_t osm_sm_mcgrp_leave(IN osm_sm_t * p_sm, IN const ib_net16_t mlid,
 		goto Exit;
 	}
 
+	osm_mgrp_holder_delete_mgrp_port(p_mgrp_holder, p_mgrp, port_guid);
 	/*
 	 * Walk the list of ports in the group, and remove the appropriate one.
 	 */
 	osm_port_remove_mgrp(p_port, mlid);
-
+	OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG," Calling sm_mgrp_process for mgrp with mlid = 0x%X\n",cl_ntoh16(mlid));
 	status = sm_mgrp_process(p_sm, p_mgrp);
 	CL_PLOCK_RELEASE(p_sm->p_lock);
 
diff --git a/opensm/opensm/osm_subnet.c b/opensm/opensm/osm_subnet.c
index ec15f8a..a6d4f4c 100644
--- a/opensm/opensm/osm_subnet.c
+++ b/opensm/opensm/osm_subnet.c
@@ -68,6 +68,7 @@
 #include <opensm/osm_perfmgr.h>
 #include <opensm/osm_event_plugin.h>
 #include <opensm/osm_qos_policy.h>
+#include <opensm/osm_mgrp_holder.h>
 
 static const char null_str[] = "(null)";
 
@@ -419,7 +420,7 @@ void osm_subn_destroy(IN osm_subn_t * const p_subn)
 	osm_switch_t *p_sw, *p_next_sw;
 	osm_remote_sm_t *p_rsm, *p_next_rsm;
 	osm_prtn_t *p_prtn, *p_next_prtn;
-	osm_mgrp_t *p_mgrp;
+	osm_mgrp_holder_t *p_osm_mgrp_holder;
 	osm_infr_t *p_infr, *p_next_infr;
 
 	/* it might be a good idea to de-allocate all known objects */
@@ -464,10 +465,10 @@ void osm_subn_destroy(IN osm_subn_t * const p_subn)
 
 	for (i = 0; i <= p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO;
 	     i++) {
-		p_mgrp = p_subn->mgroups[i];
-		p_subn->mgroups[i] = NULL;
-		if (p_mgrp)
-			osm_mgrp_delete(p_mgrp);
+		p_osm_mgrp_holder = p_subn->mgroup_holders[i];
+		if (p_osm_mgrp_holder){
+				osm_mgrp_holder_delete(p_subn, p_osm_mgrp_holder->mlid);
+		}
 	}
 
 	p_next_infr = (osm_infr_t *) cl_qlist_head(&p_subn->sa_infr_list);
-- 
1.5.5




More information about the general mailing list