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

Sasha Khapyorsky sashak at voltaire.com
Wed Mar 1 09:23:13 PST 2006


On 01:20 Mon 27 Feb     , 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.

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                   |  355 ++++++++++++++++-------
 osm/opensm/osm_prtn.c                       |  325 +++++++++++++++++++++
 osm/opensm/osm_prtn_config.c                |  413 +++++++++++++++++++++++++++
 osm/opensm/osm_sa_mcmember_record.c         |   20 +
 osm/opensm/osm_subnet.c                     |   17 +
 13 files changed, 1245 insertions(+), 209 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 97c6296..6e4e033 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.
  *
@@ -315,6 +315,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 447176a..ea7b007 100644
--- a/osm/opensm/Makefile.am
+++ b/osm/opensm/Makefile.am
@@ -80,6 +80,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 c5ba443..ed6ed79 100644
--- a/osm/opensm/main.c
+++ b/osm/opensm/main.c
@@ -182,6 +182,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"
@@ -470,7 +474,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
@@ -491,6 +495,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'},
@@ -680,6 +685,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 6ca6796..94a16ac 100644
--- a/osm/opensm/osm_opensm.c
+++ b/osm/opensm/osm_opensm.c
@@ -262,7 +262,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..cc02bac 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,254 @@ 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 )
+   }
+   else
+   {
+      *p_orig_pkey = pkey;
+      for ( block_index = 0; block_index < num_of_blocks; block_index++ )
       {
-         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 );
+         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 ) {
+	    block_found = TRUE;
+	    break;
+	 }
       }
-      else
-      {
-         /* 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
-         {
-            attr_mod = block_index;
-         }
+   }
 
-         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 */
+   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;
+   }
 
-         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
+   status = osm_pkey_mgr_update_pkey_entry(p_mgr, p_physp, block, block_index);
+
+   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",
-                     cl_ntoh64( osm_node_get_node_guid( p_node ) ),
-                     port_num );
-         }
+                     block_index,
+                     cl_ntoh64(osm_node_get_node_guid(p_node)),
+                     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 +364,54 @@ 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);
 
-   CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
+   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_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 ) )
+   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_node = p_next_node;
-      p_next_node = ( osm_node_t * ) cl_qmap_next( &p_next_node->map_item );
+      p_prtn = (osm_prtn_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++ )
-      {
-         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;
-            }
-         }
+      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_port = (osm_port_t *)p_next;
+      p_next = cl_qmap_next(p_next);
+
+      if (osm_node_get_type(osm_port_get_parent_node(p_port)) !=
+		      IB_NODE_TYPE_SWITCH) {
+         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..c53d849
--- /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, 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 = cl_hton16(cl_ntoh16(p->pkey)|0x8000);
+
+	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 "
+			"file \'%s\' was not fully processed (or does not exist).\n",
+			file_name);
+	}
+
+  _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..d818e84
--- /dev/null
+++ b/osm/opensm/osm_prtn_config.c
@@ -0,0 +1,413 @@
+/*
+ * 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 <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, 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;
+	
+	if (conf->is_ipoib)
+		osm_prtn_add_mcgroup(conf->p_log, conf->p_subn,
+				conf->p_prtn, 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) {
+		perror("fopen");
+		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 5daa70e..aef903a 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.
  *
@@ -1146,6 +1146,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, 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 b7f6afe..5f35daf 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