[openib-general] [RFC] [PATCH] OpenSM: Add functional partition manager support

Sasha Khapyorsky sashak at voltaire.com
Thu Mar 9 15:33:49 PST 2006


On 19:23 Wed 01 Mar     , Sasha Khapyorsky wrote:
> > > 
> > > There is phase 1 of partiton manager for OpenSM. Please review.
> 
> There is partition patch which includes all last changes and is updated
> against recent SVN tree.

Updated patch. Changes are:
 - clean perror() (osm_log() instead)
 - creates "dummy" MC group for non ipoib partitions
 - formatting changes
 - update against recent SVN

Sasha.


This patch implements partition management for OpenSM (Phase 1) as
described in osm/doc/OpenSM_PKey_Mgr.txt.

Basically at each heavy resweep this will:

 - recreate partition configuration
 - update pkey tables for endports
 - update switch's ports connected to endports
 - for partitions marked for IPoIB support this will also create
   appropriate multicast group, desired rate and mtu values may
   be specified

Signed-off-by: Sasha Khapyorsky <sashak at voltaire.com>
---

 osm/doc/partition-config.txt                |   98 ++++++
 osm/include/opensm/osm_base.h               |   16 +
 osm/include/opensm/osm_partition.h          |  151 ++++------
 osm/include/opensm/osm_sa_mcmember_record.h |   38 ++
 osm/include/opensm/osm_subnet.h             |    7 
 osm/opensm/Makefile.am                      |    1 
 osm/opensm/main.c                           |   11 +
 osm/opensm/osm_opensm.c                     |    2 
 osm/opensm/osm_pkey_mgr.c                   |  359 ++++++++++++++++-------
 osm/opensm/osm_prtn.c                       |  325 +++++++++++++++++++++
 osm/opensm/osm_prtn_config.c                |  417 +++++++++++++++++++++++++++
 osm/opensm/osm_sa_mcmember_record.c         |   20 +
 osm/opensm/osm_subnet.c                     |   17 +
 13 files changed, 1256 insertions(+), 206 deletions(-)

diff --git a/osm/doc/partition-config.txt b/osm/doc/partition-config.txt
new file mode 100644
index 0000000..a5d0fd0
--- /dev/null
+++ b/osm/doc/partition-config.txt
@@ -0,0 +1,98 @@
+OpenSM Partitions configuration.
+===============================
+
+The default name of OpenSM partitions configuration file is
+'/etc/osm-partitions.txt'. The default may be changed by using
+--Pconfig (-P) option with OpenSM.
+
+The default partition will be created by OpenSM unconditionally even
+when partition configuration file does not exist or cannot be accessed.
+
+The default partition has P_Key value 0x7fff. OpenSM's port will have
+full membership in default partition. all other end ports will have
+partial membership.
+
+
+File Format.
+===========
+
+Comments:
+--------
+
+Line content followed after '#' character is comment and ignored by
+parser.
+
+
+General file format:
+-------------------
+
+<Partition Definition>:<PortGUIDs list> ;
+
+
+Partition Definition:
+--------------------
+
+[PartitionName][=PKey][,flag[=value]]
+
+PartitionName - free string, will be used with logging. When omitted
+                empty string will be used.
+PKey          - P_Key value for this partition. Only low 15 bits will
+                be used. When omitted will be autogenerated.
+flag          - used to indicate IPoIB capability of this partition.
+
+Currently recognized flags are:
+
+ipoib      - indicates that this partition may be used for IPoIB, as
+             result IPoIB capable MC group will be created.
+rate=<val> - specifies rate for this IPoIB MC group (default is 3 (10Bps))
+mtu=<val>  - specifies MTU for this IPoIB MC group (default is 4 (2048))
+
+Note that values for 'rate' and 'mtu' should be specified as defined in
+IBTA specification (for example mtu=4 for 2048).
+
+
+PortGUIDs list:
+--------------
+
+[PortGUID[=full|=part]] [,PortGUID[=full|=part]] [,PortGUID] ...
+
+PortGUID     - GUID of partition member EndPort. Hexadecimal numbers
+               should start from 0x, decimal numbers are accepted too.
+full or part - indicates full or partial membership for this port. When
+               omitted (or unrecognized) partial membership is assumed.
+
+There are two useful keywords for PortGUID definition:
+
+- 'ALL' means all end ports in this subnet
+- 'SELF' means subnet manager's port.
+
+Empty list means no ports in this partition.
+
+
+Notes:
+-----
+
+White spaces are permitted between delimiters ('=', ',',':',';').
+
+The Line can be wrapped after ':' followed after Partition Definition and
+between.
+
+PartitionName does not need to be unique, PKey does need to be unique.
+If PKey is repeated then those partition configurations will be merged
+and first PartitionName will be used (see also next note).
+
+It is possible to split partition configuration in more than one
+definition, but then PKey should be explicitly specified (overwise
+different PKey values will be generated for those definitions).
+
+
+Examples:
+--------
+
+Default=0x7fff : ALL, SELF=full ;
+
+NewPartition , ipoib : 0x123456=full, 0x3456789034=part, 0x2134af2306 ;
+
+YetAnotherOne = 0x300 : SELF=full ;  
+YetAnotherOne = 0x300 : ALL=part ;  
+
diff --git a/osm/include/opensm/osm_base.h b/osm/include/opensm/osm_base.h
index 660771f..3da39a6 100644
--- a/osm/include/opensm/osm_base.h
+++ b/osm/include/opensm/osm_base.h
@@ -222,6 +222,22 @@ BEGIN_C_DECLS
 #endif
 /***********/
 
+/****d* OpenSM: Base/OSM_DEFAULT_PARTITION_CONFIG_FILE
+* NAME
+*	OSM_DEFAULT_PARTITION_CONFIG_FILE
+*
+* DESCRIPTION
+*	Specifies the default partition config file name
+*
+* SYNOPSIS
+*/
+#ifdef __WIN__
+#define OSM_DEFAULT_PARTITION_CONFIG_FILE strcat(GetOsmPath(), "osm-partitions.conf")
+#else
+#define OSM_DEFAULT_PARTITION_CONFIG_FILE "/etc/osm-partitions.conf"
+#endif
+/***********/
+
 /****d* OpenSM: Base/OSM_DEFAULT_SWEEP_INTERVAL_SECS
 * NAME
 *	OSM_DEFAULT_SWEEP_INTERVAL_SECS
diff --git a/osm/include/opensm/osm_partition.h b/osm/include/opensm/osm_partition.h
index 27678c2..369cf8a 100644
--- a/osm/include/opensm/osm_partition.h
+++ b/osm/include/opensm/osm_partition.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
  *
@@ -50,6 +50,12 @@
 #ifndef _OSM_PARTITION_H_
 #define _OSM_PARTITION_H_
 
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_map.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_subnet.h>
+
 #ifdef __cplusplus
 #  define BEGIN_C_DECLS extern "C" {
 #  define END_C_DECLS   }
@@ -94,12 +100,17 @@ BEGIN_C_DECLS
 */
 typedef struct _osm_prtn
 {
-	uint16_t						pkey;
-	cl_map							port_guid_tbl;
-
+	cl_map_item_t	map_item;
+	uint16_t	pkey;
+	cl_map_t	full_guid_tbl;
+	cl_map_t	part_guid_tbl;
+	char		name[32];
 } osm_prtn_t;
 /*
 * FIELDS
+*	map_item
+*		Linkage structure for cl_qmap.  MUST BE FIRST MEMBER!
+*
 *	pkey
 *		The IBA defined P_KEY of this Partition.
 *
@@ -111,118 +122,61 @@ typedef struct _osm_prtn
 *	Partition
 *********/
 
-/****f* OpenSM: Partition/osm_prtn_construct
+/****f* OpenSM: Partition/osm_prtn_delete
 * NAME
-*	osm_prtn_construct
+*	osm_prtn_delete
 *
 * DESCRIPTION
-*	This function constructs a Partition.
+*	This function destroys and deallocates a Partition object.
 *
 * SYNOPSIS
 */
-void osm_prtn_construct(
-	IN osm_prtn_t* const p_prtn );
+void osm_prtn_delete(
+	IN OUT osm_prtn_t** const pp_prtn );
 /*
 * PARAMETERS
-*	p_prtn
-*		[in] Pointer to a Partition to construct.
+*	pp_prtn
+*		[in][out] Pointer to a pointer to a Partition oject to
+*		delete. On return, this pointer is NULL.
 *
 * RETURN VALUE
 *	This function does not return a value.
 *
 * NOTES
-*	Allows calling osm_prtn_init, osm_prtn_destroy, and osm_prtn_is_inited.
-*
-*	Calling osm_prtn_construct is a prerequisite to calling any other
-*	method except osm_prtn_init.
+*	Performs any necessary cleanup of the specified Partition object.
 *
 * SEE ALSO
-*	Partition, osm_prtn_init, osm_prtn_destroy, osm_prtn_is_inited
+*	Partition, osm_prtn_new
 *********/
 
-/****f* OpenSM: Partition/osm_prtn_destroy
+/****f* OpenSM: Partition/osm_prtn_new
 * NAME
-*	osm_prtn_destroy
+*	osm_prtn_new
 *
 * DESCRIPTION
-*	The osm_prtn_destroy function destroys a Partition, releasing
-*	all resources.
+*	This function allocates and initializes a Partition object.
 *
 * SYNOPSIS
 */
-void osm_prtn_destroy(
-	IN osm_prtn_t* const p_prtn );
+osm_prtn_t* osm_prtn_new(
+	IN const char *name,
+	IN const uint16_t pkey );
 /*
 * PARAMETERS
-*	p_prtn
-*		[in] Pointer to a Partition to destroy.
-*
-* RETURN VALUE
-*	This function does not return a value.
-*
-* NOTES
-*	Performs any necessary cleanup of the specified Partition.
-*	Further operations should not be attempted on the destroyed object.
-*	This function should only be called after a call to osm_prtn_construct or
-*	osm_prtn_init.
-*
-* SEE ALSO
-*	Partition, osm_prtn_construct, osm_prtn_init
-*********/
-
-/****f* OpenSM: Partition/osm_prtn_init
-* NAME
-*	osm_prtn_init
-*
-* DESCRIPTION
-*	The osm_prtn_init function initializes a Partition for use.
-*
-* SYNOPSIS
-*/
-ib_api_status_t osm_prtn_init(
-	IN osm_prtn_t* const p_prtn );
-/*
-* PARAMETERS
-*	p_prtn
-*		[in] Pointer to an osm_prtn_t object to initialize.
-*
-* RETURN VALUES
-*	CL_SUCCESS if initialization was successful.
-*
-* NOTES
-*	Allows calling other Partition methods.
+*	name
+*		[in] Partition name string
 *
-* SEE ALSO
-*	Partition, osm_prtn_construct, osm_prtn_destroy,
-*	osm_prtn_is_inited
-*********/
-
-/****f* OpenSM: Partition/osm_prtn_is_inited
-* NAME
-*	osm_prtn_is_inited
-*
-* DESCRIPTION
-*	Indicates if the object has been initialized with osm_prtn_init.
-*
-* SYNOPSIS
-*/
-boolean_t osm_ptrn_is_inited(
-	IN const osm_prtn_t* const p_prtn );
-/*
-* PARAMETERS
-*	p_prtn
-*		[in] Pointer to an osm_prtn_t object.
+*	pkey
+*		[in] Partition P_Key value
 *
-* RETURN VALUES
-*	TRUE if the object was initialized successfully,
-*	FALSE otherwise.
+* RETURN VALUE
+*	Pointer to the initialize Partition object.
 *
 * NOTES
-*	The osm_prtn_construct or osm_prtn_init must be called before using
-*	this function.
+*	Allows calling other partition methods.
 *
 * SEE ALSO
-*	Partition, osm_prtn_construct, osm_prtn_init
+*	Partition
 *********/
 
 /****f* OpenSM: Partition/osm_prtn_is_guid
@@ -234,9 +188,14 @@ boolean_t osm_ptrn_is_inited(
 *
 * SYNOPSIS
 */
+static inline
 boolean_t osm_prtn_is_guid(
 	IN const osm_prtn_t* const p_prtn,
-	IN const uint64 guid );
+	IN const ib_net64_t guid )
+{
+	return (cl_map_get(&p_prtn->full_guid_tbl, guid) != NULL) ||
+		(cl_map_get(&p_prtn->part_guid_tbl, guid) != NULL);
+}
 /*
 * PARAMETERS
 *	p_prtn
@@ -254,24 +213,28 @@ boolean_t osm_prtn_is_guid(
 * SEE ALSO
 *********/
 
-/****f* OpenSM: Partition/osm_prtn_get_pkey
+/****f* OpenSM: Partition/osm_prtn_make_partitions
 * NAME
-*	osm_prtn_get_pkey
+*	osm_prtn_make_partitions
 *
 * DESCRIPTION
-*	Gets the IBA defined P_KEY value for this Partition.
+* 	Makes all partitions in subnet.
 *
 * SYNOPSIS
 */
-uint16_t osm_prtn_get_pkey(
-	IN const osm_prtn_t* const p_prtn );
+ib_api_status_t osm_prtn_make_partitions(
+	IN osm_log_t * const p_log,
+	IN osm_subn_t * const p_subn);
 /*
 * PARAMETERS
-*	p_prtn
-*		[in] Pointer to an osm_prtn_t object.
+*	p_log
+*		[in] Pointer to a log object.
+*
+*	p_subn
+*		[in] Pointer to subnet object.
 *
 * RETURN VALUES
-*	P_KEY value for this Partition.
+*	IB_SUCCESS value on success.
 *
 * NOTES
 *
diff --git a/osm/include/opensm/osm_sa_mcmember_record.h b/osm/include/opensm/osm_sa_mcmember_record.h
index 39a466c..92de861 100644
--- a/osm/include/opensm/osm_sa_mcmember_record.h
+++ b/osm/include/opensm/osm_sa_mcmember_record.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
  *
@@ -320,6 +320,42 @@ osm_mcmr_rcv_create_new_mgrp(
 *	
 *********/
 
+/****f* OpenSM: MC Member record Receiver/osm_mcmr_rcv_find_or_create_new_mgrp
+* NAME
+*	osm_mcmr_rcv_find_or_create_new_mgrp
+*
+* DESCRIPTION
+*	Create new Multicast group
+*
+* SYNOPSIS
+*/
+
+ib_api_status_t
+osm_mcmr_rcv_find_or_create_new_mgrp(
+	  IN osm_mcmr_recv_t* const p_mcmr,
+	  IN uint64_t comp_mask,
+	  IN ib_member_rec_t* const p_recvd_mcmember_rec,
+	  OUT osm_mgrp_t **pp_mgrp);
+/*
+* PARAMETERS
+*	p_mcmr
+*		[in] Pointer to an osm_mcmr_recv_t object.
+*	p_recvd_mcmember_rec
+*		[in] Received Multicast member record
+*
+*	pp_mgrp
+*		[out] pointer the osm_mgrp_t object
+*
+* RETURN VALUES
+*	IB_SUCCESS, IB_ERROR
+*
+* NOTES
+*
+*
+* SEE ALSO
+*
+*********/
+
 #define JOIN_MC_COMP_MASK	(IB_MCR_COMPMASK_MGID |		\
 							IB_MCR_COMPMASK_PORT_GID |	\
 							IB_MCR_COMPMASK_JOIN_STATE)
diff --git a/osm/include/opensm/osm_subnet.h b/osm/include/opensm/osm_subnet.h
index 0aab874..7841c29 100644
--- a/osm/include/opensm/osm_subnet.h
+++ b/osm/include/opensm/osm_subnet.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
  *
@@ -73,6 +73,8 @@ BEGIN_C_DECLS
 #define OSM_SUBNET_VECTOR_CAPACITY			256
 
 
+struct _osm_opensm_t;
+
 /****h* OpenSM/Subnet
 * NAME
 *	Subnet
@@ -220,6 +222,7 @@ typedef struct _osm_subn_opt
   uint8_t                  log_flags;
   char *                   dump_files_dir;
   char *                   log_file;
+  const char *             partition_config_file;
   boolean_t                accum_log_file;
   boolean_t                console;
   cl_map_t                 port_prof_ignore_guids;
@@ -399,6 +402,7 @@ typedef struct _osm_subn_opt
 */
 typedef struct _osm_subn
 {
+  struct _osm_opensm_t *p_osm;
   cl_qmap_t						sw_guid_tbl;
   cl_qmap_t						node_guid_tbl;
   cl_qmap_t						port_guid_tbl;
@@ -644,6 +648,7 @@ osm_subn_destroy(
 ib_api_status_t
 osm_subn_init(
 	IN osm_subn_t* const p_subn,
+	IN struct _osm_opensm_t * const p_osm,
 	IN const osm_subn_opt_t* const p_opt );
 /*
 * PARAMETERS
diff --git a/osm/opensm/Makefile.am b/osm/opensm/Makefile.am
index 1c63180..4014ea7 100644
--- a/osm/opensm/Makefile.am
+++ b/osm/opensm/Makefile.am
@@ -81,6 +81,7 @@ opensm_SOURCES = main.c osm_console.c os
 		 osm_state_mgr_ctrl.c osm_subnet.c \
 		 osm_sweep_fail_ctrl.c osm_sw_info_rcv.c \
 		 osm_sw_info_rcv_ctrl.c osm_switch.c \
+		 osm_prtn.c osm_prtn_config.c \
 		 osm_trap_rcv.c osm_trap_rcv_ctrl.c \
 		 osm_ucast_mgr.c osm_ucast_updn.c \
 		 osm_vl15intf.c osm_vl_arb_rcv.c\
diff --git a/osm/opensm/main.c b/osm/opensm/main.c
index b8ecd52..efb278d 100644
--- a/osm/opensm/main.c
+++ b/osm/opensm/main.c
@@ -224,6 +224,10 @@ show_usage(void)
           "          This option will cause deletion of the log file\n"
           "          (if it previously exists). By default, the log file\n"
           "          is accumulative.\n\n");
+  printf( "-P\n"
+          "--Pconfig\n"
+          "          This option defines the optional partition configurationi file.\n"
+	  "          The default name is \'" OSM_DEFAULT_PARTITION_CONFIG_FILE "\'.\n\n");
   printf( "-y\n"
           "--stay_on_fatal\n"
           "          This option will cause SM not to exit on fatal initialization\n"
@@ -511,7 +515,7 @@ main(
   boolean_t             cache_options = FALSE;
   char                 *ignore_guids_file_name = NULL;
   uint32_t              val;
-  const char * const    short_option = "i:f:ed:g:l:s:t:a:uvVhorcy";
+  const char * const    short_option = "i:f:ed:g:l:s:t:a:P:uvVhorcy";
 
   /*
     In the array below, the 2nd parameter specified the number
@@ -532,6 +536,7 @@ main(
       {  "D",             1, NULL, 'D'},
       {  "log_file",      1, NULL, 'f'},
       {  "erase_log_file",0, NULL, 'e'},
+      {  "Pconfig",       1, NULL, 'P'},
       {  "maxsmps",       1, NULL, 'n'},
       {  "console",       0, NULL, 'q'},
       {  "V",             0, NULL, 'V'},
@@ -719,6 +724,10 @@ main(
       printf(" Creating new log file\n");
       break;
 
+    case 'P':
+      opt.partition_config_file = optarg;
+      break;
+
     case 'y':
       opt.exit_on_fatal = FALSE;
       printf(" Staying on fatal initialization errors\n");
diff --git a/osm/opensm/osm_opensm.c b/osm/opensm/osm_opensm.c
index 54d0ae3..06a04e5 100644
--- a/osm/opensm/osm_opensm.c
+++ b/osm/opensm/osm_opensm.c
@@ -215,7 +215,7 @@ osm_opensm_init(
    if( status != IB_SUCCESS )
       goto Exit;
 
-   status = osm_subn_init( &p_osm->subn, p_opt );
+   status = osm_subn_init( &p_osm->subn, p_osm, p_opt );
    if( status != IB_SUCCESS )
       goto Exit;
 
diff --git a/osm/opensm/osm_pkey_mgr.c b/osm/opensm/osm_pkey_mgr.c
index 14ed2db..3be7619 100644
--- a/osm/opensm/osm_pkey_mgr.c
+++ b/osm/opensm/osm_pkey_mgr.c
@@ -56,6 +56,7 @@
 #include <complib/cl_debug.h>
 #include <opensm/osm_node.h>
 #include <opensm/osm_pkey_mgr.h>
+#include <opensm/osm_partition.h>
 
 /**********************************************************************
  **********************************************************************/
@@ -107,121 +108,262 @@ osm_pkey_mgr_init(
 
 /**********************************************************************
  **********************************************************************/
-boolean_t
+static ib_api_status_t
+osm_pkey_mgr_update_pkey_entry(
+   IN const osm_pkey_mgr_t * const p_mgr,
+   IN const osm_physp_t * p_physp,
+   IN const ib_pkey_table_t * block,
+   IN const uint16_t block_index )
+{
+   osm_madw_context_t context;
+   osm_node_t *p_node = osm_physp_get_node_ptr( p_physp );
+   uint32_t attr_mod;
+
+   context.pkey_context.node_guid = osm_node_get_node_guid( p_node );
+   context.pkey_context.port_guid = osm_physp_get_port_guid( p_physp );
+   context.pkey_context.set_method = TRUE;
+   attr_mod = block_index;
+   if ( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH )
+      attr_mod |= osm_physp_get_port_num( p_physp ) << 16;
+   return osm_req_set( p_mgr->p_req, osm_physp_get_dr_path_ptr( p_physp ),
+                       ( uint8_t * ) block, sizeof( *block ),
+                       IB_MAD_ATTR_P_KEY_TABLE,
+                       cl_hton32( attr_mod ), CL_DISP_MSGID_NONE, &context );
+}
+
+/**********************************************************************
+ **********************************************************************/
+
+/*
+ * Send a new entry for the pkey table for this port when this pkey
+ * does not exist. Update existed entry when membership was changed.
+ */
+
+static boolean_t
 __osm_pkey_mgr_process_physical_port(
    IN const osm_pkey_mgr_t * const p_mgr,
-   IN osm_node_t * p_node,
-   IN uint8_t port_num,
+   IN const ib_net16_t pkey,
    IN osm_physp_t * p_physp )
 {
-   boolean_t return_val = FALSE; /* TRUE if IB_DEFAULT_PKEY was inserted */
-   osm_madw_context_t context;
+   boolean_t return_val = FALSE; /* TRUE if pkey was inserted or updated */
+   ib_api_status_t status;
+   osm_node_t *p_node = osm_physp_get_node_ptr( p_physp );
    ib_pkey_table_t *block = NULL;
    uint16_t block_index;
    uint16_t num_of_blocks;
    const osm_pkey_tbl_t *p_pkey_tbl;
-   uint32_t attr_mod;
+   ib_net16_t *p_orig_pkey;
    uint32_t i;
-   ib_net16_t pkey;
-   ib_api_status_t status;
-   boolean_t block_with_empty_entry_found;
+   boolean_t block_found = FALSE;
 
    OSM_LOG_ENTER( p_mgr->p_log, __osm_pkey_mgr_process_physical_port );
 
-   /*
-    * Send a new entry for the pkey table for this node that includes
-    * IB_DEFAULT_PKEY when IB_DEFAULT_PARTIAL_PKEY or IB_DEFAULT_PKEY 
-    * don't exist 
-    */
-   if ( ( osm_physp_has_pkey( p_mgr->p_log,
-                              IB_DEFAULT_PKEY,
-                              p_physp ) == FALSE ) &&
-        ( osm_physp_has_pkey( p_mgr->p_log,
-                              IB_DEFAULT_PARTIAL_PKEY, p_physp ) == FALSE ) )
-   {
-      context.pkey_context.node_guid = osm_node_get_node_guid( p_node );
-      context.pkey_context.port_guid = osm_physp_get_port_guid( p_physp );
-      context.pkey_context.set_method = TRUE;
-
-      p_pkey_tbl = osm_physp_get_pkey_tbl( p_physp );
-      num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl );
-      block_with_empty_entry_found = FALSE;
+   p_pkey_tbl = osm_physp_get_pkey_tbl( p_physp );
+   num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl );
 
+   p_orig_pkey = cl_map_get( &p_pkey_tbl->keys, ib_pkey_get_base( pkey ) );
+
+   if ( p_orig_pkey && *p_orig_pkey == pkey )
+   {
+      if ( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
+      {
+         osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
+                  "__osm_pkey_mgr_process_physical_port:  "
+                  "No need to insert %04x for node 0x%016" PRIx64
+                  " port %u\n",
+                  cl_ntoh16( pkey ),
+                  cl_ntoh64( osm_node_get_node_guid( p_node ) ),
+                  osm_physp_get_port_num( p_physp ) );
+      }
+      goto _done;
+   }
+   else if ( !p_orig_pkey )
+   {
       for ( block_index = 0; block_index < num_of_blocks; block_index++ )
       {
          block = osm_pkey_tbl_block_get( p_pkey_tbl, block_index );
          for ( i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++ )
          {
-            pkey = block->pkey_entry[i];
-            if ( ib_pkey_is_invalid( pkey ) )
+            if ( ib_pkey_is_invalid( block->pkey_entry[i] ) )
             {
-               block->pkey_entry[i] = IB_DEFAULT_PKEY;
-               block_with_empty_entry_found = TRUE;
+               block->pkey_entry[i] = pkey;
+               block_found = TRUE;
                break;
             }
          }
-         if ( block_with_empty_entry_found )
+         if ( block_found )
          {
             break;
          }
       }
-
-      if ( block_with_empty_entry_found == FALSE )
-      {
-         osm_log( p_mgr->p_log, OSM_LOG_ERROR,
-                  "__osm_pkey_mgr_process_physical_port: ERR 0501: "
-                  "No empty entry was found to insert IB_DEFAULT_PKEY for node "
-                  "0x%016" PRIx64 " and port %u\n",
-                  cl_ntoh64( osm_node_get_node_guid( p_node ) ), port_num );
-      }
-      else
+   }
+   else
+   {
+      *p_orig_pkey = pkey;
+      for ( block_index = 0; block_index < num_of_blocks; block_index++ )
       {
-         /* Building the attribute modifier */
-         if ( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH )
-         {
-            /* Port num | Block Index */
-            attr_mod = port_num << 16 | block_index;
-         }
-         else
+         block = osm_pkey_tbl_block_get( p_pkey_tbl, block_index );
+         i = p_orig_pkey - block->pkey_entry;
+         if ( i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK )
          {
-            attr_mod = block_index;
+            block_found = TRUE;
+            break;
          }
+      }
+   }
+
+   if ( block_found == FALSE )
+   {
+      osm_log( p_mgr->p_log, OSM_LOG_ERROR,
+               "__osm_pkey_mgr_process_physical_port: ERR 0501: "
+               "No empty entry was found to insert %04x for node "
+               "0x%016" PRIx64 " and port %u\n",
+               cl_ntoh16( pkey ),
+               cl_ntoh64( osm_node_get_node_guid( p_node ) ),
+               osm_physp_get_port_num( p_physp ) );
+      goto _done;
+   }
 
-         status = osm_req_set( p_mgr->p_req,
-                               osm_physp_get_dr_path_ptr( p_physp ),
-                               ( uint8_t * ) block,
-                               sizeof( *block ),
-                               IB_MAD_ATTR_P_KEY_TABLE,
-                               cl_hton32( attr_mod ),
-                               CL_DISP_MSGID_NONE, &context );
-         return_val = TRUE;     /*IB_DEFAULT_PKEY was inserted */
+   status =
+      osm_pkey_mgr_update_pkey_entry( p_mgr, p_physp, block, block_index );
 
-         if ( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
-         {
-            osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
-                     "__osm_pkey_mgr_process_physical_port:  "
-                     "IB_DEFAULT_PKEY was inserted for node 0x%016" PRIx64
+   if ( status != IB_SUCCESS )
+   {
+      osm_log( p_mgr->p_log, OSM_LOG_ERROR,
+               "__osm_pkey_mgr_process_physical_port:  "
+               "osm_pkey_mgr_update_pkey_entry() failed to update "
+               "pkey table block %d for node 0x%016" PRIx64 " and port %u\n",
+               block_index,
+               cl_ntoh64( osm_node_get_node_guid( p_node ) ),
+               osm_physp_get_port_num( p_physp ) );
+      goto _done;
+   }
+
+   return_val = TRUE;           /* pkey was inserted/updated */
+
+   if ( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
+   {
+      osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
+               "__osm_pkey_mgr_process_physical_port:  "
+               "%04x was inserted for node 0x%016" PRIx64
+               " and port %u\n",
+               cl_ntoh16( pkey ),
+               cl_ntoh64( osm_node_get_node_guid( p_node ) ),
+               osm_physp_get_port_num( p_physp ) );
+   }
+
+ _done:
+   OSM_LOG_EXIT( p_mgr->p_log );
+   return ( return_val );
+}
+
+
+/**********************************************************************
+ **********************************************************************/
+static void
+osm_pkey_mgr_update_peer_port(
+   const osm_pkey_mgr_t * const p_mgr,
+   const osm_port_t * const p_port )
+{
+   osm_physp_t *p, *peer;
+   osm_node_t *p_node;
+   ib_pkey_table_t *block, *peer_block;
+   const osm_pkey_tbl_t *p_pkey_tbl, *p_peer_pkey_tbl;
+   uint16_t block_index;
+   uint16_t num_of_blocks;
+   ib_api_status_t status = IB_SUCCESS;
+
+   p = osm_port_get_default_phys_ptr( p_port );
+   if ( !osm_physp_is_valid( p ) )
+      return;
+   peer = osm_physp_get_remote( p );
+   if ( !peer || !osm_physp_is_valid( peer ) )
+      return;
+   p_node = osm_physp_get_node_ptr( peer );
+   if ( osm_node_get_type( p_node ) == IB_NODE_TYPE_CA )
+      return;
+
+   p_pkey_tbl = osm_physp_get_pkey_tbl( p );
+   p_peer_pkey_tbl = osm_physp_get_pkey_tbl( peer );
+   num_of_blocks = osm_pkey_tbl_get_num_blocks( p_pkey_tbl );
+   if ( num_of_blocks > osm_pkey_tbl_get_num_blocks( p_peer_pkey_tbl ) )
+      num_of_blocks = osm_pkey_tbl_get_num_blocks( p_peer_pkey_tbl );
+
+   for ( block_index = 0; block_index < num_of_blocks; block_index++ )
+   {
+      block = osm_pkey_tbl_block_get( p_pkey_tbl, block_index );
+      peer_block = osm_pkey_tbl_block_get( p_peer_pkey_tbl, block_index );
+      if ( cl_memcmp( peer_block, block, sizeof( *block ) ) )
+      {
+         cl_memcpy( peer_block, block, sizeof( *block ) );
+         status =
+            osm_pkey_mgr_update_pkey_entry( p_mgr, peer, peer_block,
+                                            block_index );
+         if ( status != IB_SUCCESS )
+            osm_log( p_mgr->p_log, OSM_LOG_ERROR,
+                     "osm_pkey_mgr_update_peer_port: "
+                     "osm_pkey_mgr_update_pkey_entry() failed to update "
+                     "pkey table block %d for node 0x%016" PRIx64
                      " and port %u\n",
+                     block_index,
                      cl_ntoh64( osm_node_get_node_guid( p_node ) ),
-                     port_num );
-         }
+                     osm_physp_get_port_num( peer ) );
       }
    }
-   else 
+
+   if ( num_of_blocks && status == IB_SUCCESS &&
+        osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
    {
-      /* default key or partial default key already exist */
-      if ( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
+      osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
+               "osm_pkey_mgr_update_peer_port: "
+               "pkey table was updated for node 0x%016" PRIx64
+               " and port %u\n",
+               cl_ntoh64( osm_node_get_node_guid( p_node ) ),
+               osm_physp_get_port_num( peer ) );
+   }
+}
+
+/**********************************************************************
+ **********************************************************************/
+static boolean_t
+osm_pkey_mgr_process_partition_table(
+   const osm_pkey_mgr_t * const p_mgr,
+   const osm_prtn_t * const p_prtn,
+   const boolean_t full )
+{
+   const cl_map_t *p_tbl = full ?
+      &p_prtn->full_guid_tbl : &p_prtn->part_guid_tbl;
+   cl_map_iterator_t i, i_next;
+   ib_net16_t pkey = p_prtn->pkey;
+   osm_physp_t *p_physp;
+   boolean_t result = FALSE;
+
+   if ( full )
+      pkey = cl_hton16( cl_ntoh16( pkey ) | 0x8000 );
+
+   i_next = cl_map_head( p_tbl );
+   while ( i_next != cl_map_end( p_tbl ) )
+   {
+      i = i_next;
+      i_next = cl_map_next( i );
+      p_physp = cl_map_obj( i );
+      if ( p_physp && osm_physp_is_valid( p_physp ) &&
+           __osm_pkey_mgr_process_physical_port( p_mgr, pkey, p_physp ) )
       {
-        osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
-                 "__osm_pkey_mgr_process_physical_port:  "
-                 "No need to insert IB_DEFAULT_PKEY for node 0x%016" PRIx64
-                 " port %u\n",
-                 cl_ntoh64( osm_node_get_node_guid( p_node ) ), port_num );
+         result = TRUE;
+         if ( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
+            osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
+                     "osm_pkey_mgr_process_partition_table:  "
+                     "Adding %04x for pkey table of node "
+                     "0x%016" PRIx64 " port %u\n",
+                     cl_ntoh16( pkey ),
+                     cl_ntoh64( osm_node_get_node_guid
+                                ( osm_physp_get_node_ptr( p_physp ) ) ),
+                     osm_physp_get_port_num( p_physp ) );
       }
    }
 
-   OSM_LOG_EXIT( p_mgr->p_log );
-   return ( return_val );
+   return result;
 }
 
 /**********************************************************************
@@ -230,51 +372,56 @@ osm_signal_t
 osm_pkey_mgr_process(
    IN const osm_pkey_mgr_t * const p_mgr )
 {
-   cl_qmap_t *p_node_guid_tbl;
-   osm_node_t *p_node;
-   osm_node_t *p_next_node;
-   uint8_t port_num;
-   osm_physp_t *p_physp;
+   cl_qmap_t *p_tbl;
+   cl_map_item_t *p_next;
+   osm_prtn_t *p_prtn;
+   osm_port_t *p_port;
    osm_signal_t result = OSM_SIGNAL_DONE;
 
    CL_ASSERT( p_mgr );
 
    OSM_LOG_ENTER( p_mgr->p_log, osm_pkey_mgr_process );
 
-   p_node_guid_tbl = &p_mgr->p_subn->node_guid_tbl;
-
    CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
 
-   p_next_node = ( osm_node_t * ) cl_qmap_head( p_node_guid_tbl );
-   while ( p_next_node != ( osm_node_t * ) cl_qmap_end( p_node_guid_tbl ) )
+   if ( osm_prtn_make_partitions( p_mgr->p_log, p_mgr->p_subn ) !=
+        IB_SUCCESS )
+   {
+      osm_log( p_mgr->p_log, OSM_LOG_ERROR, "osm_pkey_mgr_process: "
+               "osm_prtn_make_partitions() is failed.\n" );
+      goto _err;
+   }
+
+   p_tbl = &p_mgr->p_subn->prtn_pkey_tbl;
+
+   p_next = cl_qmap_head( p_tbl );
+   while ( p_next != cl_qmap_end( p_tbl ) )
+   {
+      p_prtn = ( osm_prtn_t * ) p_next;
+      p_next = cl_qmap_next( p_next );
+
+      if ( osm_pkey_mgr_process_partition_table( p_mgr, p_prtn, FALSE ) )
+         result = OSM_SIGNAL_DONE_PENDING;
+      if ( osm_pkey_mgr_process_partition_table( p_mgr, p_prtn, TRUE ) )
+         result = OSM_SIGNAL_DONE_PENDING;
+   }
+
+   p_tbl = &p_mgr->p_subn->port_guid_tbl;
+
+   p_next = cl_qmap_head( p_tbl );
+   while ( p_next != cl_qmap_end( p_tbl ) )
    {
-      p_node = p_next_node;
-      p_next_node = ( osm_node_t * ) cl_qmap_next( &p_next_node->map_item );
+      p_port = ( osm_port_t * ) p_next;
+      p_next = cl_qmap_next( p_next );
 
-      for ( port_num = 0; port_num < osm_node_get_num_physp( p_node );
-            port_num++ )
+      if ( osm_node_get_type( osm_port_get_parent_node( p_port ) ) !=
+           IB_NODE_TYPE_SWITCH )
       {
-         p_physp = osm_node_get_physp_ptr( p_node, port_num );
-         if ( osm_physp_is_valid( p_physp ) )
-         {
-            if ( __osm_pkey_mgr_process_physical_port
-                 ( p_mgr, p_node, port_num, p_physp ) )
-            {
-               if ( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
-               {
-                  osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
-                           "osm_pkey_mgr_process:  "
-                           "Adding IB_DEFAULT_PKEY for pkey table of node "
-                           "0x%016" PRIx64 " port %u\n",
-                           cl_ntoh64( osm_node_get_node_guid( p_node ) ),
-                           port_num );
-               }
-               result = OSM_SIGNAL_DONE_PENDING;
-            }
-         }
+         osm_pkey_mgr_update_peer_port( p_mgr, p_port );
       }
    }
 
+ _err:
    CL_PLOCK_RELEASE( p_mgr->p_lock );
    OSM_LOG_EXIT( p_mgr->p_log );
    return ( result );
diff --git a/osm/opensm/osm_prtn.c b/osm/opensm/osm_prtn.c
new file mode 100644
index 0000000..64fc1b4
--- /dev/null
+++ b/osm/opensm/osm_prtn.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2006 Voltaire, Inc. 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.
+ *
+ * $Id$
+ */
+
+
+/*
+ * Abstract:
+ *    Implementation of osm_prtn_t.
+ * This object represents an IBA partition.
+ * This object is part of the opensm family of objects.
+ *
+ * Environment:
+ *    Linux User Mode
+ *
+ * $Revision$
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+
+#include <iba/ib_types.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_sa.h>
+#include <opensm/osm_multicast.h>
+
+
+extern int osm_prtn_config_parse_file(osm_log_t * const p_log,
+		osm_subn_t * const p_subn,
+		const char *file_name);
+
+
+static uint16_t global_pkey_counter;
+
+/*
+ *
+ */
+
+osm_prtn_t* osm_prtn_new(
+	IN const char *name,
+	IN const uint16_t pkey )
+{
+	osm_prtn_t *p = cl_zalloc(sizeof(*p));
+	if (!p)
+		return NULL;
+	p->pkey = pkey;
+	cl_map_construct(&p->full_guid_tbl);
+	cl_map_init(&p->full_guid_tbl, 32);
+	cl_map_construct(&p->part_guid_tbl);
+	cl_map_init(&p->part_guid_tbl, 32);
+
+	if (name && *name)
+		strncpy(p->name, name, sizeof(p->name));
+	else
+		snprintf(p->name, sizeof(p->name), "%04x", cl_ntoh16(pkey));
+
+	return p;
+}
+
+void osm_prtn_delete(
+	IN OUT osm_prtn_t** const pp_prtn )
+{
+	osm_prtn_t *p = *pp_prtn;
+	cl_map_remove_all(&p->full_guid_tbl);
+	cl_map_destroy(&p->full_guid_tbl);
+	cl_map_remove_all(&p->part_guid_tbl);
+	cl_map_destroy(&p->part_guid_tbl);
+	cl_free(p);
+	*pp_prtn = NULL;
+}
+
+
+ib_api_status_t osm_prtn_add_port(osm_log_t *p_log, osm_subn_t *p_subn,
+		osm_prtn_t *p, ib_net64_t guid, boolean_t full)
+{
+	cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl;
+	ib_api_status_t status = IB_SUCCESS;
+	cl_map_t *p_tbl;
+	osm_port_t *p_port;
+	osm_physp_t *p_physp;
+
+	p_port = (osm_port_t *)cl_qmap_get(p_port_tbl, guid);
+	if (!p_port || p_port == (osm_port_t *)cl_qmap_end(p_port_tbl)) {
+		osm_log(p_log, OSM_LOG_VERBOSE, "osm_prtn_add_port: "
+			"port 0x%" PRIx64 " not found.\n",
+			cl_ntoh64(guid));
+		return status;
+	}
+
+	p_physp = osm_port_get_default_phys_ptr(p_port);
+	if (!p_physp) {
+		osm_log(p_log, OSM_LOG_VERBOSE, "osm_prtn_add_port: "
+			"no physical for port 0x%" PRIx64 "\n",
+			cl_ntoh64(guid));
+		return status;
+	}
+
+	if (osm_prtn_is_guid(p, guid)) {
+		osm_log(p_log, OSM_LOG_VERBOSE, "osm_prtn_add_port: "
+			"port 0x%" PRIx64 " already in "
+			"partition \'%s\' (%04x). Will overwrite.\n",
+			cl_ntoh64(guid), p->name, cl_ntoh16(p->pkey));
+	}
+
+	p_tbl = (full == TRUE) ? &p->full_guid_tbl : &p->part_guid_tbl ;
+
+	if (cl_map_insert(p_tbl, guid, p_physp) == NULL)
+		return IB_INSUFFICIENT_MEMORY;
+
+	return status;
+}
+
+
+ib_api_status_t osm_prtn_add_all(osm_log_t *p_log, osm_subn_t *p_subn,
+		osm_prtn_t *p, boolean_t full)
+{
+	cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl;
+	cl_map_item_t *p_item;
+	osm_port_t *p_port;
+	ib_api_status_t status = IB_SUCCESS;
+
+	p_item = cl_qmap_head(p_port_tbl);
+	while (p_item != cl_qmap_end(p_port_tbl)) {
+		p_port = (osm_port_t *)p_item;
+		p_item = cl_qmap_next(p_item);
+		status = osm_prtn_add_port(p_log, p_subn, p,
+				osm_port_get_guid(p_port), full);
+		if (status != IB_SUCCESS)
+			goto _err;
+	}
+
+  _err:
+	return status;
+}
+
+
+ib_api_status_t osm_prtn_add_mcgroup(osm_log_t *p_log,
+		osm_subn_t *p_subn, osm_prtn_t *p,
+		unsigned is_ipoib, uint8_t rate, uint8_t mtu)
+{
+	ib_member_rec_t mc_rec;
+	ib_net64_t comp_mask;
+	ib_net16_t pkey;
+	osm_mgrp_t *p_mgrp = NULL;
+	osm_sa_t *p_sa = &p_subn->p_osm->sa;
+	ib_api_status_t status = IB_SUCCESS;
+
+	pkey = is_ipoib ? cl_hton16(cl_ntoh16(p->pkey)|0x8000) : p->pkey;
+
+	cl_memclr(&mc_rec, sizeof(mc_rec));
+
+	mc_rec.mgid = osm_ipoib_mgid; /* this is ipv4 broadcast */
+	cl_memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey));
+
+	mc_rec.qkey = CL_HTON32(0x0b1b);
+	mc_rec.mtu = mtu ? mtu : 4; /*  2048 Bytes */
+	mc_rec.tclass = 0;
+	mc_rec.pkey = pkey;
+	mc_rec.rate = rate ? rate : 0x3; /* 10Gb/sec */
+	mc_rec.pkt_life = OSM_DEFAULT_SUBNET_TIMEOUT;
+	mc_rec.sl_flow_hop = OSM_DEFAULT_SL << 28;
+	/* Note: scope needs to be consistent with MGID */
+	mc_rec.scope_state = 0x21;
+
+	/* don't update rate, mtu */
+	comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_RATE;
+
+	status = osm_mcmr_rcv_find_or_create_new_mgrp(&p_sa->mcmr_rcv,
+		comp_mask, &mc_rec, &p_mgrp);
+
+	if (!p_mgrp || status != IB_SUCCESS)
+		osm_log( p_log, OSM_LOG_ERROR,
+			"osm_prtn_add_mcgroup:"
+			" failed to create mc group with %04x pkey\n",
+			cl_ntoh16(pkey));
+
+	return status;
+}
+
+
+static uint16_t __generate_pkey(osm_subn_t *p_subn)
+{
+	uint16_t pkey;
+	cl_qmap_t *m = &p_subn->prtn_pkey_tbl;
+	while ( global_pkey_counter < cl_ntoh16(IB_DEFAULT_PARTIAL_PKEY) - 1) {
+		pkey = ++global_pkey_counter;
+		pkey = cl_hton16(pkey);
+		if (cl_qmap_get(m, pkey) == cl_qmap_end(m))
+			return pkey;
+	}
+	return 0;
+}
+
+osm_prtn_t *osm_prtn_make_new(osm_log_t *p_log, osm_subn_t *p_subn,
+		const char *name, uint16_t pkey)
+{
+	osm_prtn_t *p = NULL, *p_check;
+
+	if (pkey == 0 && !(pkey = __generate_pkey(p_subn)))
+		return NULL;
+
+	if (cl_ntoh16(pkey)&0x8000) {
+		pkey = cl_hton16(cl_ntoh16(pkey)&~0x8000);
+		osm_log(p_log, OSM_LOG_VERBOSE,
+			"osm_prtn_make_new: pkey was striped for"
+			" partition \'%s\' (%04x)\n",
+			name, cl_ntoh16(pkey));
+	}
+
+	p = osm_prtn_new(name, pkey);
+	if (!p) {
+		osm_log(p_log, OSM_LOG_ERROR,
+			"osm_prtn_make_new: Unable to create"
+			" partition \'%s\' (%04x)\n",
+			name, cl_ntoh16(pkey));
+		return NULL;
+	}
+
+	p_check = (osm_prtn_t *)cl_qmap_insert(&p_subn->prtn_pkey_tbl,
+			p->pkey, &p->map_item);
+	if (p != p_check) {
+		osm_log(p_log, OSM_LOG_VERBOSE,
+			"osm_prtn_make_new: Duplicated partition"
+			" definition: \'%s\' (%04x) prev name \'%s\'"
+			" - will use it.\n",
+			name, cl_ntoh16(pkey), p_check->name);
+		osm_prtn_delete(&p);
+		p = p_check;
+	}
+
+	return p;
+}
+
+
+static ib_api_status_t osm_prtn_make_default(osm_log_t * const p_log,
+		osm_subn_t * const p_subn)
+{
+	ib_api_status_t status = IB_UNKNOWN_ERROR;
+	osm_prtn_t *p;
+	p = osm_prtn_make_new(p_log, p_subn,
+			"Default", IB_DEFAULT_PARTIAL_PKEY);
+	if (!p)
+		goto _err;
+	status = osm_prtn_add_all(p_log, p_subn, p, FALSE);
+	if (status != IB_SUCCESS)
+		goto _err;;
+	cl_map_remove(&p->part_guid_tbl, p_subn->sm_port_guid);
+	status = osm_prtn_add_port(p_log, p_subn, p,
+			p_subn->sm_port_guid, TRUE);
+  _err:
+	return status;
+}
+
+
+ib_api_status_t osm_prtn_make_partitions(osm_log_t * const p_log,
+		osm_subn_t * const p_subn)
+{
+	const char *file_name;
+	ib_api_status_t status = IB_SUCCESS;
+	osm_prtn_t *p, *p_next;
+
+	file_name = p_subn->opt.partition_config_file ?
+			p_subn->opt.partition_config_file :
+			"/etc/osm-partitions.conf";
+
+	/* cl_qmap uses self addresses we cannot just save
+	   qmap state and clean it later, so clean all now */
+	p_next = (osm_prtn_t *)cl_qmap_head(&p_subn->prtn_pkey_tbl);
+	while (p_next != (osm_prtn_t *)cl_qmap_end(&p_subn->prtn_pkey_tbl)) {
+		p = p_next;
+		p_next = (osm_prtn_t *)cl_qmap_next(&p->map_item);
+		osm_prtn_delete(&p);
+	}
+	cl_qmap_init(&p_subn->prtn_pkey_tbl);
+
+	global_pkey_counter = 0;
+
+	status = osm_prtn_make_default(p_log, p_subn);
+	if(status != IB_SUCCESS)
+		goto _err;
+
+	if (osm_prtn_config_parse_file(p_log, p_subn, file_name)) {
+		osm_log(p_log, OSM_LOG_VERBOSE,
+			"osm_prtn_make_partitions: Partition configuration "
+			"was not fully processed.\n");
+	}
+
+  _err:
+	return status;
+}
diff --git a/osm/opensm/osm_prtn_config.c b/osm/opensm/osm_prtn_config.c
new file mode 100644
index 0000000..8b8a945
--- /dev/null
+++ b/osm/opensm/osm_prtn_config.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2006 Voltaire, Inc. 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.
+ *
+ * $Id$
+ */
+
+
+/*
+ * Abstract:
+ *    Implementation of opensm partition management configuration
+ *
+ * Environment:
+ *    Linux User Mode
+ *
+ * $Revision$
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <iba/ib_types.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_log.h>
+
+
+#if __WORDSIZE == 64
+#define STRTO_IB_NET64(str, end, base) strtoul(str, end, base)
+#else
+#define STRTO_IB_NET64(str, end, base) strtoull(str, end, base)
+#endif
+
+#define  PARSERR(log, lnum, fmt, arg...) { \
+	osm_log(log, OSM_LOG_ERROR, \
+		"\nPARSE ERROR: line %d: " fmt "\n", (lnum), ##arg ); \
+	fprintf(stderr, \
+		"\nPARSE ERROR: line %d: " fmt "\n", (lnum), ##arg ); \
+}
+
+#define  PARSEWARN(log, lnum, fmt, arg...) \
+	osm_log(log, OSM_LOG_VERBOSE, \
+		"PARSE WARN: line %d: " fmt , (lnum), ##arg )
+
+/*
+ */
+
+
+struct part_conf {
+	osm_log_t *p_log;
+	osm_subn_t *p_subn;
+	osm_prtn_t *p_prtn;
+	unsigned    is_ipoib, mtu, rate;
+};
+
+
+extern osm_prtn_t *osm_prtn_make_new(osm_log_t *p_log, osm_subn_t *p_subn,
+		const char *name, uint16_t pkey);
+extern ib_api_status_t osm_prtn_add_all(osm_log_t *p_log,
+		osm_subn_t *p_subn, osm_prtn_t *p, boolean_t full);
+extern ib_api_status_t osm_prtn_add_port(osm_log_t *p_log,
+		osm_subn_t *p_subn, osm_prtn_t *p, ib_net64_t guid,
+		boolean_t full);
+extern ib_api_status_t osm_prtn_add_mcgroup(osm_log_t *p_log,
+		osm_subn_t *p_subn, osm_prtn_t *p,
+		unsigned is_ipoib, uint8_t rate, uint8_t mtu);
+
+static int partition_create(unsigned lineno, struct part_conf *conf,
+		char *name, char *id, char *flag, char *flag_val)
+{
+	uint16_t pkey;
+
+	if (!id && name && isdigit(*name)) {
+		id = name;
+		name = NULL;
+	}
+
+	if (id) {
+		char *end;
+		pkey = strtoul(id, &end, 0);
+		if (end == id || *end)
+			return -1;
+	}
+	else
+		pkey = 0;
+
+	conf->p_prtn = osm_prtn_make_new(conf->p_log, conf->p_subn,
+			name, cl_hton16(pkey));
+	if (!conf->p_prtn)
+		return -1;
+	
+	osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn,
+			conf->is_ipoib, conf->rate, conf->mtu);
+
+	return 0;
+}
+
+
+static int partition_add_flag(unsigned lineno, struct part_conf *conf,
+				char *flag, char *val)
+{
+	int len = strlen(flag);
+	if (!strncmp(flag, "ipoib", len)) {
+		conf->is_ipoib = 1;
+	}
+	else if (!strncmp(flag, "mtu", len)) {
+		if (!val || (conf->mtu = strtoul(val, NULL, 0)) == 0)
+			PARSEWARN(conf->p_log, lineno,
+				"flag \'mtu\' requires valid value"
+				" - skipped.\n");
+	}
+	else if (!strncmp(flag, "rate", len)) {
+		if (!val || (conf->rate = strtoul(val, NULL, 0)) == 0)
+			PARSEWARN(conf->p_log, lineno,
+				"flag \'rate\' requires valid value"
+				" - skipped.\n");
+	}
+	else {
+		PARSEWARN(conf->p_log, lineno,
+			"unrecognized partition flag \'%s\'"
+			" - ignored.\n", flag);
+	}
+	return 0;
+}
+
+
+static int partition_add_port(unsigned lineno, struct part_conf *conf,
+		char *name, char *flag)
+{
+	osm_prtn_t *p = conf->p_prtn;
+	ib_net64_t guid;
+	boolean_t full = FALSE;
+
+	if (!name || !*name || !strncmp(name, "NONE", strlen(name)))
+		return 0;
+
+	if (flag) {
+		if(!strncmp(flag, "full", strlen(flag)))
+			full = TRUE;
+		else if(strncmp(flag, "partial", strlen(flag))) {
+			PARSEWARN(conf->p_log, lineno,
+				"unrecognized port flag \'%s\' -"
+				" suppose \'partial\'\n", flag);
+		}
+	}
+
+	if (!strncmp(name, "ALL", strlen(name))) {
+		return osm_prtn_add_all(conf->p_log, conf->p_subn, p,
+				full) == IB_SUCCESS ? 0 : -1;
+	}
+	else if (!strncmp(name, "SELF", strlen(name))) {
+		guid = cl_ntoh64(conf->p_subn->sm_port_guid);
+	}
+	else {
+		char *end;
+		guid = STRTO_IB_NET64(name, &end, 0);
+		if (!guid || *end)
+			return -1;
+	}
+
+	if (osm_prtn_add_port(conf->p_log, conf->p_subn, p,
+				cl_hton64(guid), full) != IB_SUCCESS)
+		return -1;
+
+	return 0;
+}
+
+
+/* conf file parser */
+
+#define STRIP_HEAD_SPACES(p) while (*(p) == ' ' || *(p) == '\t' || \
+		*(p) == '\n') { (p)++; }
+#define STRIP_TAIL_SPACES(p) { char *q = (p) + strlen(p); \
+				while ( q != (p) && ( *q == '\0' || \
+					*q == ' ' || *q == '\t' || \
+					*q == '\n')) { *q-- = '\0'; }; }
+
+static int parse_name_token(char *str, char **name, char **val)
+{
+	int len = 0;
+	char *p, *q;
+
+	*name = *val = NULL;
+
+	p = str;
+
+	while (*p == ' ' || *p == '\t' || *p == '\n')
+		p++;
+
+	q = strchr(p, '=');
+	if (q)
+		*q++ = '\0';
+
+	len = strlen(str) + 1;
+	str = q;
+
+	q = p + strlen(p);
+	while ( q != p &&
+		( *q == '\0' || *q == ' ' || *q == '\t' || *q == '\n'))
+		*q-- = '\0';
+
+	*name = p;
+
+	p = str;
+	if (!p)
+		return len;
+
+	while (*p == ' ' || *p == '\t' || *p == '\n')
+		p++;
+
+	q = p + strlen(p);
+	len += q - str + 1;
+	while ( q != p &&
+		( *q == '\0' || *q == ' ' || *q == '\t' || *q == '\n'))
+		*q-- = '\0';
+	*val = p;
+
+	return len;
+}
+
+
+static struct part_conf *new_part_conf(osm_log_t *p_log, osm_subn_t *p_subn)
+{
+	static struct part_conf part;
+	struct part_conf *conf = ∂
+	memset(conf, 0, sizeof(*conf));
+	conf->p_log = p_log;
+	conf->p_subn = p_subn;
+	conf->p_prtn = NULL;
+	return conf;
+}
+
+static int flush_part_conf(struct part_conf *conf)
+{
+	memset(conf, 0, sizeof(*conf));
+	return 0;
+}
+
+
+static int parse_part_conf(struct part_conf *conf, char *str, int lineno)
+{
+	int ret, len = 0;
+	char *name, *id, *flag, *flval;
+	char *q, *p;
+
+	p = str;
+	if (*p == '\t' || *p == '\0' || *p == '\n')
+		p++;
+
+	len += p - str;
+	str = p;
+
+	if (conf->p_prtn)
+		goto skip_header;
+
+	q = strchr(p, ':');
+	if (!q) {
+		PARSERR(conf->p_log, lineno,
+			"no partition definition found\n");
+		return -1;
+	}
+
+	*q++ = '\0';
+	str = q;
+
+	name = id = flag = flval = NULL;
+
+	q = strchr(p, ',');
+	if (q)
+		*q = '\0';
+
+	ret = parse_name_token(p, &name, &id);
+	p += ret;
+	len += ret;
+
+	while (q) {
+		flag = flval = NULL;
+		q = strchr(p, ',');
+		if (q)
+			*q++ = '\0';
+		ret = parse_name_token(p, &flag, &flval);
+		if (!flag) {
+			PARSERR(conf->p_log, lineno,
+				"bad partition flags\n");
+			return -1;
+		}
+		p += ret;
+		len += ret;
+		partition_add_flag(lineno, conf, flag, flval);
+	}
+
+	if (p != str || (partition_create(lineno, conf,
+					name, id, flag, flval) < 0)) {
+		PARSERR(conf->p_log, lineno,
+			"bad partition definition\n");
+		return -1;
+	}
+
+  skip_header:
+	do {
+		name = flag = NULL;
+		q = strchr(p, ',');
+		if (q)
+			*q++ = '\0';
+		ret = parse_name_token(p, &name, &flag);
+		if (partition_add_port(lineno, conf, name, flag) < 0) {
+			PARSERR(conf->p_log, lineno,
+				"bad PortGUID\n");
+			return -1;
+		}
+		p += ret;
+		len += ret;
+	} while (q);
+
+	return len;
+}
+
+int osm_prtn_config_parse_file(osm_log_t *p_log, osm_subn_t *p_subn,
+		const char *file_name)
+{
+	char line[1024];
+	struct part_conf *conf = NULL;
+	FILE *file;
+	int lineno;
+
+	file = fopen(file_name, "r");
+	if (!file) {
+		osm_log(p_log, OSM_LOG_VERBOSE,
+				"osm_prtn_config_parse_file: "
+				"cannot open config file \'%s\': %s\n",
+				file_name, strerror(errno));
+		return -1;
+	}
+
+	lineno = 0;
+
+	while (fgets(line, sizeof(line) - 1, file) != NULL) {
+		char *q, *p = line;
+
+		lineno++;
+
+		p = line;
+
+		q = strchr(p, '#');
+		if (q)
+			*q = '\0';
+
+		do {
+			int len;
+			while (*p == ' ' || *p == '\t' || *p == '\n')
+				p++;
+			if (*p == '\0')
+				break;
+
+			if (!conf &&
+				!(conf = new_part_conf(p_log, p_subn))) {
+				PARSERR(p_log, lineno,
+					"internal: cannot create config.\n");
+				break;
+			}
+
+			q = strchr(p, ';');
+			if (q)
+				*q = '\0';
+
+			len = parse_part_conf(conf, p, lineno);
+			if (len < 0) {
+				break;
+			}
+
+			p += len;
+
+			if (q) {
+				flush_part_conf(conf);
+				conf = NULL;
+			}
+		} while (q);
+	}
+
+	fclose(file);
+
+	return 0;
+}
diff --git a/osm/opensm/osm_sa_mcmember_record.c b/osm/opensm/osm_sa_mcmember_record.c
index 2c63adb..d41dc5a 100644
--- a/osm/opensm/osm_sa_mcmember_record.c
+++ b/osm/opensm/osm_sa_mcmember_record.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
  *
@@ -1217,6 +1217,24 @@ __mgrp_request_is_realizable(
 }
   
 /**********************************************************************
+ Call this function to find or create a new mgrp.
+**********************************************************************/
+ib_api_status_t
+osm_mcmr_rcv_find_or_create_new_mgrp(
+  IN osm_mcmr_recv_t* const p_rcv,
+  IN ib_net64_t comp_mask,
+  IN ib_member_rec_t* const p_recvd_mcmember_rec,
+  OUT osm_mgrp_t **pp_mgrp)
+{
+  ib_api_status_t status;
+  status = __get_mgrp_by_mgid(p_rcv, p_recvd_mcmember_rec, pp_mgrp);
+  if (status == IB_SUCCESS)
+     return status;
+  return osm_mcmr_rcv_create_new_mgrp(p_rcv, comp_mask,
+		  p_recvd_mcmember_rec, NULL, pp_mgrp);
+}
+
+/**********************************************************************
  Call this function to create a new mgrp.
 **********************************************************************/
 ib_api_status_t
diff --git a/osm/opensm/osm_subnet.c b/osm/opensm/osm_subnet.c
index 5bc84a7..df185c5 100644
--- a/osm/opensm/osm_subnet.c
+++ b/osm/opensm/osm_subnet.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
  *
@@ -53,11 +53,13 @@
 
 #include <complib/cl_debug.h>
 #include <opensm/osm_subnet.h>
+#include <opensm/osm_opensm.h>
 #include <opensm/osm_log.h>
 #include <opensm/osm_madw.h>
 #include <opensm/osm_port.h>
 #include <opensm/osm_switch.h>
 #include <opensm/osm_remote_sm.h>
+#include <opensm/osm_partition.h>
 #include <opensm/osm_node.h>
 #include <opensm/osm_multicast.h>
 #include <opensm/osm_inform.h>
@@ -97,6 +99,7 @@ osm_subn_destroy(
   osm_port_t      *p_port, *p_next_port;
   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, *p_next_mgrp;
   osm_infr_t      *p_infr, *p_next_infr;
 
@@ -135,6 +138,14 @@ osm_subn_destroy(
     cl_free( p_rsm );
   }
 
+  p_next_prtn = (osm_prtn_t*)cl_qmap_head( &p_subn->prtn_pkey_tbl );
+  while( p_next_prtn != (osm_prtn_t*)cl_qmap_end( &p_subn->prtn_pkey_tbl ) )
+  {
+    p_prtn = p_next_prtn;
+    p_next_prtn = (osm_prtn_t*)cl_qmap_next( &p_prtn->map_item );
+    osm_prtn_delete( &p_prtn );
+  }
+
   p_next_mgrp = (osm_mgrp_t*)cl_qmap_head( &p_subn->mgrp_mlid_tbl );
   while( p_next_mgrp != (osm_mgrp_t*)cl_qmap_end( &p_subn->mgrp_mlid_tbl ) )
   {
@@ -167,10 +178,13 @@ osm_subn_destroy(
 ib_api_status_t
 osm_subn_init(
   IN osm_subn_t* const p_subn,
+  IN osm_opensm_t * const p_osm,
   IN const osm_subn_opt_t* const p_opt )
 {
   cl_status_t status;
 
+  p_subn->p_osm = p_osm;
+
   status = cl_ptr_vector_init( &p_subn->node_lid_tbl,
                                OSM_SUBNET_VECTOR_MIN_SIZE,
                                OSM_SUBNET_VECTOR_GROW_SIZE );
@@ -428,6 +442,7 @@ osm_subn_set_default_opt(
     p_opt->dump_files_dir = OSM_DEFAULT_TMP_DIR;
 
   p_opt->log_file = OSM_DEFAULT_LOG_FILE;
+  p_opt->partition_config_file = OSM_DEFAULT_PARTITION_CONFIG_FILE;
   p_opt->accum_log_file = TRUE;
   p_opt->port_profile_switch_nodes = FALSE;
   p_opt->max_port_profile = 0xffffffff;



More information about the general mailing list