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 <[EMAIL PROTECTED]>
---

 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 = &part;
+       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;
_______________________________________________
openib-general mailing list
[email protected]
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to