[openib-general] [PATCH] opensm: dump/restore SA database

Sasha Khapyorsky sashak at voltaire.com
Wed Nov 22 03:34:14 PST 2006


This adds OpenSM SA database DB dumping and restoring functionality.

In verbose mode OpenSM will dump SA DB (existing multicast groups,
services and InformInfo) into dump file which named "opensm-sa.dump"
and located under standard OpenSM dump directory (/var/log by default).

If option -S is specified and SA DB dump file name is provided OpenSM
will try to restore SA database from this file. And if succeed will
don't ask for clients reregistration at subnet bring-up.

Signed-off-by: Sasha Khapyorsky <sashak at voltaire.com>
---
 osm/include/opensm/osm_sa.h         |   43 +++-
 osm/include/opensm/osm_subnet.h     |    8 +
 osm/opensm/main.c                   |   20 +-
 osm/opensm/osm_lid_mgr.c            |    1 +
 osm/opensm/osm_opensm.c             |    3 +
 osm/opensm/osm_sa.c                 |  630 +++++++++++++++++++++++++++++++++++
 osm/opensm/osm_sa_mcmember_record.c |   14 +-
 osm/opensm/osm_state_mgr.c          |    8 +
 osm/opensm/osm_subnet.c             |   11 +
 9 files changed, 729 insertions(+), 9 deletions(-)

diff --git a/osm/include/opensm/osm_sa.h b/osm/include/opensm/osm_sa.h
index 0d450ad..70d9bb0 100644
--- a/osm/include/opensm/osm_sa.h
+++ b/osm/include/opensm/osm_sa.h
@@ -54,8 +54,8 @@
 #include <complib/cl_event.h>
 #include <complib/cl_thread.h>
 #include <complib/cl_timer.h>
-#include <opensm/osm_stats.h>
 #include <complib/cl_dispatcher.h>
+#include <opensm/osm_stats.h>
 #include <opensm/osm_subnet.h>
 #include <vendor/osm_vendor.h>
 #include <opensm/osm_mad_pool.h>
@@ -445,6 +445,47 @@ osm_sa_bind(
 * SEE ALSO
 *********/
 
+struct _osm_opensm_t;
+/****f* OpenSM: SA/osm_sa_db_file_dump
+* NAME
+*	osm_sa_db_file_dump
+*
+* DESCRIPTION
+*	Dumps the SA DB to the dump file.
+*
+* SYNOPSIS
+*/
+int osm_sa_db_file_dump(struct _osm_opensm_t *p_osm);
+/*
+* PARAMETERS
+*	p_osm
+*		[in] Pointer to an osm_opensm_t object.
+*
+* RETURN VALUES
+*	None
+*
+*********/
+
+/****f* OpenSM: SA/osm_sa_db_file_load
+* NAME
+*	osm_sa_db_file_load
+*
+* DESCRIPTION
+*	Loads SA DB from the file.
+*
+* SYNOPSIS
+*/
+int osm_sa_db_file_load(struct _osm_opensm_t *p_osm);
+/*
+* PARAMETERS
+*	p_osm
+*		[in] Pointer to an osm_opensm_t object.
+*
+* RETURN VALUES
+*	0 on success, other value on failure.
+*
+*********/
+
 END_C_DECLS
 
 #endif		/* _OSM_SA_H_ */
diff --git a/osm/include/opensm/osm_subnet.h b/osm/include/opensm/osm_subnet.h
index d9895ec..2b22ea5 100644
--- a/osm/include/opensm/osm_subnet.h
+++ b/osm/include/opensm/osm_subnet.h
@@ -279,6 +279,7 @@ typedef struct _osm_subn_opt
   char *                   lid_matrix_dump_file;
   char *                   ucast_dump_file;
   char *                   updn_guid_file;
+  char *                   sa_db_file;
   boolean_t                exit_on_fatal;
   boolean_t                honor_guid2lid_file;
   osm_qos_options_t        qos_options;
@@ -287,6 +288,7 @@ typedef struct _osm_subn_opt
   osm_qos_options_t        qos_swe_options;
   osm_qos_options_t        qos_rtr_options;
   boolean_t                enable_quirks;
+  boolean_t                no_clients_rereg;
 } osm_subn_opt_t;
 /*
 * FIELDS
@@ -443,6 +445,9 @@ typedef struct _osm_subn_opt
 *	updn_guid_file
 *		Pointer to name of the UPDN guid file given by User
 *
+*	sa_db_file
+*		Name of the SA database file.
+*
 *	exit_on_fatal
 *		If TRUE (default) - SM will exit on fatal subnet initialization issues.
 *		If FALSE - SM will not exit.
@@ -474,6 +479,9 @@ typedef struct _osm_subn_opt
 *		Enable high risk new features and not fully qualified 
 *		hardware specific work arounds
 *
+*	no_clients_rereg
+*		When TRUE disables clients reregistration request.
+*
 * SEE ALSO
 *	Subnet object
 *********/
diff --git a/osm/opensm/main.c b/osm/opensm/main.c
index 752b546..6c83018 100644
--- a/osm/opensm/main.c
+++ b/osm/opensm/main.c
@@ -48,18 +48,18 @@
 #  include <config.h>
 #endif /* HAVE_CONFIG_H */
 
-#include "stdio.h"
+#include <stdio.h>
 #include <stdlib.h>
 #include <getopt.h>
 #include <unistd.h>
+#include <complib/cl_types.h>
+#include <complib/cl_debug.h>
+#include <vendor/osm_vendor_api.h>
 #include <opensm/osm_version.h>
 #ifdef OSM_VENDOR_INTF_OPENIB
 #include <opensm/osm_svn_revision.h>
 #endif
 #include <opensm/osm_opensm.h>
-#include <complib/cl_types.h>
-#include <complib/cl_debug.h>
-#include <vendor/osm_vendor_api.h>
 #include <opensm/osm_console.h>
 
 /********************************************************************
@@ -186,6 +186,10 @@ show_usage(void)
           "--ucast_file <file name>\n"
           "          This option specifies name of the unicast dump file\n"
           "          from where switch forwarding tables will be loaded.\n\n");
+  printf( "-S\n"
+          "--sadb_file <file name>\n"
+          "          This option specifies name of the SA DB dump file\n"
+          "          from where SA database will be loaded.\n\n");
   printf ("-a\n"
           "--add_guid_file <path to file>\n"
           "          Set the root nodes for the Up/Down routing algorithm\n"
@@ -537,7 +541,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:L:s:t:a:R:M:U:P:NQvVhorcyx";
+  const char * const    short_option = "i:f:ed:g:l:L:s:t:a:R:M:U:S:P:NQvVhorcyx";
 
   /*
     In the array below, the 2nd parameter specified the number
@@ -573,6 +577,7 @@ main(
       {  "routing_engine",1, NULL, 'R'},
       {  "lid_matrix_file",1, NULL, 'M'},
       {  "ucast_file"    ,1, NULL, 'U'},
+      {  "sadb_file"     ,1, NULL, 'S'},
       {  "add_guid_file", 1, NULL, 'a'},
       {  "cache-options", 0, NULL, 'c'},
       {  "stay_on_fatal", 0, NULL, 'y'},
@@ -812,6 +817,11 @@ main(
       printf(" Ucast dump file is \'%s\'\n", optarg);
       break;
 
+    case 'S':
+      opt.sa_db_file = optarg;
+      printf(" SA DB file is \'%s\'\n", optarg);
+      break;
+
     case 'a':
       /*
         Specifies port guids file
diff --git a/osm/opensm/osm_lid_mgr.c b/osm/opensm/osm_lid_mgr.c
index da0b7a0..f2601dc 100644
--- a/osm/opensm/osm_lid_mgr.c
+++ b/osm/opensm/osm_lid_mgr.c
@@ -1276,6 +1276,7 @@ __osm_lid_mgr_set_physp_pi(
 
   if ( ( p_mgr->p_subn->first_time_master_sweep == TRUE || 
          new_port == TRUE ) &&
+       !p_mgr->p_subn->opt.no_clients_rereg &&
        ( (p_old_pi->capability_mask & IB_PORT_CAP_HAS_CLIENT_REREG) != 0 ) )
     ib_port_info_set_client_rereg( p_pi, 1 );
   else
diff --git a/osm/opensm/osm_opensm.c b/osm/opensm/osm_opensm.c
index 7c0ad7b..2ce7b36 100644
--- a/osm/opensm/osm_opensm.c
+++ b/osm/opensm/osm_opensm.c
@@ -165,6 +165,9 @@ osm_opensm_destroy(
    /* shut down the dispatcher - so no new messages cross */
    cl_disp_shutdown( &p_osm->disp );
 
+   /* dump SA DB */
+   osm_sa_db_file_dump(p_osm);
+
    /* do the destruction in reverse order as init */
    if (p_osm->routing_engine.delete)
      p_osm->routing_engine.delete(p_osm->routing_engine.context);
diff --git a/osm/opensm/osm_sa.c b/osm/opensm/osm_sa.c
index 1446e15..5d81454 100644
--- a/osm/opensm/osm_sa.c
+++ b/osm/opensm/osm_sa.c
@@ -51,6 +51,10 @@
 #endif /* HAVE_CONFIG_H */
 
 #include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <complib/cl_qmap.h>
 #include <complib/cl_passivelock.h>
 #include <complib/cl_debug.h>
@@ -62,6 +66,10 @@
 #include <opensm/osm_subnet.h>
 #include <opensm/osm_mad_pool.h>
 #include <opensm/osm_msgdef.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_service.h>
 
 #define  OSM_SA_INITIAL_TID_VALUE 0xabc
 
@@ -529,3 +537,625 @@ osm_sa_bind(
   OSM_LOG_EXIT( p_sa->p_log );
   return( status );
 }
+
+/**********************************************************************
+ **********************************************************************/
+/*
+ *  SA DB Dumper
+ *
+ */
+
+struct opensm_dump_context {
+	osm_opensm_t *p_osm;
+	FILE *file;
+};
+
+static int
+opensm_dump_to_file(osm_opensm_t *p_osm, const char *file_name,
+		    void (*dump_func)(osm_opensm_t *p_osm, FILE *file))
+{
+	char path[1024];
+	FILE  *file;
+
+	snprintf(path, sizeof(path), "%s/%s",
+		 p_osm->subn.opt.dump_files_dir, file_name);
+
+	file = fopen(path, "w");
+	if (!file) {
+		osm_log(&p_osm->log, OSM_LOG_ERROR,
+			"opensm_dump_to_file: ERR 0000: "
+			"cannot open file \'%s\': %s\n",
+			file_name, strerror(errno));
+		return -1;
+	}
+
+	chmod(path, S_IRUSR|S_IWUSR);
+
+	dump_func(p_osm, file);
+
+	fclose(file);
+	return 0;
+}
+
+static void
+mcast_mgr_dump_one_port(cl_map_item_t *p_map_item, void *cxt)
+{
+	FILE *file = ((struct opensm_dump_context *)cxt)->file;
+	osm_mcm_port_t *p_mcm_port = (osm_mcm_port_t *)p_map_item;
+
+	fprintf(file, "mcm_port: "
+		"port_gid=0x%016" PRIx64 ":0x%016" PRIx64 " "
+		"scope_state=0x%02x proxy_join=0x%x" "\n\n",
+		cl_ntoh64(p_mcm_port->port_gid.unicast.prefix),
+		cl_ntoh64(p_mcm_port->port_gid.unicast.interface_id),
+		p_mcm_port->scope_state,
+		p_mcm_port->proxy_join);
+}
+
+static void
+sa_dump_one_mgrp(cl_map_item_t *p_map_item, void *cxt)
+{
+	struct opensm_dump_context dump_context;
+	osm_opensm_t *p_osm = ((struct opensm_dump_context *)cxt)->p_osm;
+	FILE *file = ((struct opensm_dump_context *)cxt)->file;
+	osm_mgrp_t *p_mgrp = (osm_mgrp_t *)p_map_item;
+
+	fprintf(file, "MC Group 0x%04x %s:"
+		" mgid=0x%016" PRIx64 ":0x%016" PRIx64
+		" port_gid=0x%016" PRIx64 ":0x%016" PRIx64
+		" qkey=0x%08x mlid=0x%04x mtu=0x%02x tclass=0x%02x"
+		" pkey=0x%04x rate=0x%02x pkt_life=0x%02x sl_flow_hop=0x%08x"
+		" scope_state=0x%02x proxy_join=0x%x" "\n\n",
+		cl_ntoh16(p_mgrp->mlid),
+		p_mgrp->well_known ? " (well known)" : "",
+		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix),
+		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id),
+		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.prefix),
+		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.interface_id),
+		cl_ntoh32(p_mgrp->mcmember_rec.qkey),
+		cl_ntoh16(p_mgrp->mcmember_rec.mlid),
+		p_mgrp->mcmember_rec.mtu,
+		p_mgrp->mcmember_rec.tclass,
+		cl_ntoh16(p_mgrp->mcmember_rec.pkey),
+		p_mgrp->mcmember_rec.rate,
+		p_mgrp->mcmember_rec.pkt_life,
+		cl_ntoh32(p_mgrp->mcmember_rec.sl_flow_hop),
+		p_mgrp->mcmember_rec.scope_state,
+		p_mgrp->mcmember_rec.proxy_join
+		);
+
+	dump_context.p_osm = p_osm;
+	dump_context.file = file;
+
+	cl_qmap_apply_func(&p_mgrp->mcm_port_tbl,
+			   mcast_mgr_dump_one_port, &dump_context);
+}
+
+static void
+sa_dump_one_inform(cl_list_item_t *p_list_item, void *cxt)
+{
+	FILE *file = ((struct opensm_dump_context *)cxt)->file;
+	osm_infr_t *p_infr = (osm_infr_t *)p_list_item;
+	ib_inform_info_record_t *p_iir = &p_infr->inform_record;
+
+	fprintf(file, "InformInfo Record:"
+		" subscriber_gid=0x%016" PRIx64 ":0x%016" PRIx64
+		" subscriber_enum=0x%x"
+		" InformInfo:"
+		" gid=0x%016" PRIx64 ":0x%016" PRIx64
+		" lid_range_begin=0x%x"
+		" lid_range_end=0x%x"
+		" is_generic=0x%x"
+		" subscribe=0x%x"
+		" trap_type=0x%x"
+		" trap_num=0x%x"
+		" qpn_resp_time_val=0x%x"
+		" node_type=0x%06x"
+		" rep_addr: lid=0x%04x path_bits=0x%02x static_rate=0x%02x"
+		" remote_qp=0x%08x remote_qkey=0x%08x pkey=0x%04x sl=0x%02x"
+		"\n\n",
+		cl_ntoh64(p_iir->subscriber_gid.unicast.prefix),
+		cl_ntoh64(p_iir->subscriber_gid.unicast.interface_id),
+		cl_ntoh16(p_iir->subscriber_enum),
+		cl_ntoh64(p_iir->inform_info.gid.unicast.prefix),
+		cl_ntoh64(p_iir->inform_info.gid.unicast.interface_id),
+		cl_ntoh16(p_iir->inform_info.lid_range_begin),
+		cl_ntoh16(p_iir->inform_info.lid_range_end),
+		p_iir->inform_info.is_generic,
+		p_iir->inform_info.subscribe,
+		cl_ntoh16(p_iir->inform_info.trap_type),
+		cl_ntoh16(p_iir->inform_info.g_or_v.generic.trap_num),
+		cl_ntoh32(p_iir->inform_info.g_or_v.generic.qpn_resp_time_val),
+		cl_ntoh32(ib_inform_info_get_node_type(&p_iir->inform_info)),
+		cl_ntoh16(p_infr->report_addr.dest_lid),
+		p_infr->report_addr.path_bits,
+		p_infr->report_addr.static_rate,
+		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qp),
+		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qkey),
+		cl_ntoh16(p_infr->report_addr.addr_type.gsi.pkey),
+		p_infr->report_addr.addr_type.gsi.service_level);
+}
+
+static void
+sa_dump_one_service(cl_list_item_t *p_list_item, void *cxt)
+{
+	FILE *file = ((struct opensm_dump_context *)cxt)->file;
+	osm_svcr_t *p_svcr = (osm_svcr_t *)p_list_item;
+	ib_service_record_t *p_sr = &p_svcr->service_record;
+
+	fprintf(file, "Service Record: id=0x%016" PRIx64
+		" gid=0x%016" PRIx64 ":0x%016" PRIx64
+		" pkey=0x%x"
+		" lease=0x%x"
+		" key=0x%02x%02x%02x%02x%02x%02x%02x%02x"
+		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
+		" name=\'%s\'"
+		" data8=0x%02x%02x%02x%02x%02x%02x%02x%02x"
+		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
+		" data16=0x%04x%04x%04x%04x:0x%04x%04x%04x%04x"
+		" data32=0x%08x%08x:0x%08x%08x"
+		" data64=0x%016" PRIx64 ":0x%016" PRIx64
+		" modified_time=0x%x lease_period=0x%x\n\n",
+		cl_ntoh64( p_sr->service_id ),
+		cl_ntoh64( p_sr->service_gid.unicast.prefix ),
+		cl_ntoh64( p_sr->service_gid.unicast.interface_id ),
+		cl_ntoh16( p_sr->service_pkey ),
+		cl_ntoh32( p_sr->service_lease ),
+		p_sr->service_key[0], p_sr->service_key[1],
+		p_sr->service_key[2], p_sr->service_key[3],
+		p_sr->service_key[4], p_sr->service_key[5],
+		p_sr->service_key[6], p_sr->service_key[7],
+		p_sr->service_key[8], p_sr->service_key[9],
+		p_sr->service_key[10], p_sr->service_key[11],
+		p_sr->service_key[12], p_sr->service_key[13],
+		p_sr->service_key[14], p_sr->service_key[15],
+		p_sr->service_name,
+		p_sr->service_data8[0], p_sr->service_data8[1],
+		p_sr->service_data8[2], p_sr->service_data8[3],
+		p_sr->service_data8[4], p_sr->service_data8[5],
+		p_sr->service_data8[6], p_sr->service_data8[7],
+		p_sr->service_data8[8], p_sr->service_data8[9],
+		p_sr->service_data8[10], p_sr->service_data8[11],
+		p_sr->service_data8[12], p_sr->service_data8[13],
+		p_sr->service_data8[14], p_sr->service_data8[15],
+		cl_ntoh16(p_sr->service_data16[0]),
+		cl_ntoh16(p_sr->service_data16[1]),
+		cl_ntoh16(p_sr->service_data16[2]),
+		cl_ntoh16(p_sr->service_data16[3]),
+		cl_ntoh16(p_sr->service_data16[4]),
+		cl_ntoh16(p_sr->service_data16[5]),
+		cl_ntoh16(p_sr->service_data16[6]),
+		cl_ntoh16(p_sr->service_data16[7]),
+		cl_ntoh32(p_sr->service_data32[0]),
+		cl_ntoh32(p_sr->service_data32[1]),
+		cl_ntoh32(p_sr->service_data32[2]),
+		cl_ntoh32(p_sr->service_data32[3]),
+		cl_ntoh64(p_sr->service_data64[0]),
+		cl_ntoh64(p_sr->service_data64[1]),
+		p_svcr->modified_time, p_svcr->lease_period);
+}
+
+static void
+sa_dump_all_sa(osm_opensm_t *p_osm, FILE *file)
+{
+	struct opensm_dump_context dump_context;
+
+	dump_context.p_osm = p_osm;
+	dump_context.file = file;
+	osm_log(&p_osm->log, OSM_LOG_DEBUG, "sa_dump_all_sa: Dump multicat:\n");
+	cl_plock_acquire(&p_osm->lock);
+	cl_qmap_apply_func(&p_osm->subn.mgrp_mlid_tbl,
+			   sa_dump_one_mgrp, &dump_context);
+	osm_log(&p_osm->log, OSM_LOG_DEBUG, "sa_dump_all_sa: Dump inform:\n");
+	cl_qlist_apply_func(&p_osm->subn.sa_infr_list,
+			    sa_dump_one_inform, &dump_context);
+	osm_log(&p_osm->log, OSM_LOG_DEBUG, "sa_dump_all_sa: Dump services:\n");
+	cl_qlist_apply_func(&p_osm->subn.sa_sr_list,
+			    sa_dump_one_service, &dump_context);
+	cl_plock_release(&p_osm->lock);
+}
+
+int osm_sa_db_file_dump(osm_opensm_t *p_osm)
+{
+	return opensm_dump_to_file(p_osm, "opensm-sa.dump", sa_dump_all_sa);
+}
+
+/*
+ *  SA DB Loader
+ *
+ */
+
+osm_mgrp_t *load_mcgroup(osm_opensm_t *p_osm, ib_net16_t mlid,
+			 ib_member_rec_t *p_mcm_rec, unsigned well_known)
+{
+	ib_net64_t comp_mask;
+	cl_map_item_t *p_next;
+	osm_mgrp_t *p_mgrp;
+
+	cl_plock_excl_acquire(&p_osm->lock);
+
+	if ((p_next = cl_qmap_get(&p_osm->subn.mgrp_mlid_tbl, mlid)) !=
+	     cl_qmap_end(&p_osm->subn.mgrp_mlid_tbl)) {
+		p_mgrp = (osm_mgrp_t *)p_next;
+		if (!memcmp(&p_mgrp->mcmember_rec.mgid, &p_mcm_rec->mgid,
+			    sizeof(ib_gid_t))) {
+			osm_log(&p_osm->log, OSM_LOG_DEBUG,
+				"load_mcgroup: mgrp %04x is already here.",
+				cl_ntoh16(mlid));
+			goto _out;
+		}
+		osm_log(&p_osm->log, OSM_LOG_VERBOSE,
+			"load_mcgroup: mlid %04x is already used by another "
+			"MC group. Will request clients reregistration.\n",
+			cl_ntoh16(mlid));
+		p_mgrp = NULL;
+		goto _out;
+        }
+
+	comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL
+			| IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL;
+	if (osm_mcmr_rcv_find_or_create_new_mgrp(&p_osm->sa.mcmr_rcv,
+						 comp_mask, p_mcm_rec,
+						 &p_mgrp) != IB_SUCCESS ||
+	    !p_mgrp || p_mgrp->mlid != mlid) {
+		osm_log(&p_osm->log, OSM_LOG_ERROR,
+			"load_mcgroup: cannot create MC group with mlid "
+			"0x%04x and mgid 0x%016" PRIx64 ":0x%016" PRIx64 "\n",
+			cl_ntoh16(mlid),
+			cl_ntoh64(p_mcm_rec->mgid.unicast.prefix),
+			cl_ntoh64(p_mcm_rec->mgid.unicast.interface_id));
+		p_mgrp=NULL;
+	}
+	else if (well_known)
+		p_mgrp->well_known = TRUE;
+
+  _out:
+	cl_plock_release(&p_osm->lock);
+
+	return p_mgrp;
+}
+
+static int load_svcr(osm_opensm_t *p_osm, ib_service_record_t *sr,
+		     uint32_t modified_time, uint32_t lease_period)
+{
+	osm_svcr_t *p_svcr;
+	int ret = 0;
+
+	cl_plock_excl_acquire(&p_osm->lock);
+
+	if(osm_svcr_get_by_rid(&p_osm->subn, &p_osm->log, sr)) {
+		osm_log(&p_osm->log, OSM_LOG_VERBOSE,
+			"load_svcr ServiceRecord already exists.\n");
+		goto _out;
+	}
+
+	if (!(p_svcr = osm_svcr_new(sr))) {
+		osm_log(&p_osm->log, OSM_LOG_ERROR,
+			"load_svcr: cannot allocate new service struct\n");
+		ret = -1;
+		goto _out;
+	}
+
+	p_svcr->modified_time = modified_time;
+	p_svcr->lease_period = lease_period;
+
+	osm_log(&p_osm->log, OSM_LOG_DEBUG,
+		"load_svcr: adding ServiceRecord...\n");
+
+	osm_svcr_insert_to_db(&p_osm->subn, &p_osm->log, p_svcr);
+
+	if (lease_period != 0xffffffff)
+		cl_timer_trim(&p_osm->sa.sr_rcv.sr_timer, 1000);
+
+  _out:
+	cl_plock_release(&p_osm->lock);
+
+	return ret;
+}
+
+static int load_infr(osm_opensm_t *p_osm, ib_inform_info_record_t *iir,
+		     osm_mad_addr_t *addr)
+{
+	osm_infr_t infr, *p_infr;
+	int ret = 0;
+
+	infr.h_bind = p_osm->sa.mad_ctrl.h_bind;
+	infr.p_infr_rcv = &p_osm->sa.infr_rcv;
+	/* other possible way to restore mad_addr partially is
+	   to exract qpn from InfromInfo and to find lid by gid */
+	infr.report_addr = *addr;
+	infr.inform_record = *iir;
+
+	cl_plock_excl_acquire(&p_osm->lock);
+	if (osm_infr_get_by_rec(&p_osm->subn, &p_osm->log, &infr)) {
+		osm_log(&p_osm->log, OSM_LOG_VERBOSE,
+			"load_infr: InformInfo Record already exists.\n");
+		goto _out;
+	}
+
+	if (!(p_infr = osm_infr_new(&infr))) {
+		osm_log(&p_osm->log, OSM_LOG_ERROR,
+			"load_infr: cannot allocate new infr struct\n");
+		ret = -1;
+		goto _out;
+	}
+
+	osm_log(&p_osm->log, OSM_LOG_DEBUG,
+		"load_infr: adding InformInfo Record...\n");
+
+	osm_infr_insert_to_db(&p_osm->subn, &p_osm->log, p_infr);
+
+  _out:
+	cl_plock_release(&p_osm->lock);
+
+	return ret;
+}
+
+
+#define UNPACK_FUNC(name,x) \
+int unpack_##name##x(char *p, uint##x##_t *val_ptr) \
+{ \
+	char *q; \
+	unsigned long long num; \
+	num = strtoull(p, &q, 16); \
+	if (num > ~((uint##x##_t)0x0) \
+	    || q == p || (!isspace(*q) && *q != ':')) { \
+		*val_ptr = 0; \
+		return -1; \
+	} \
+	*val_ptr = cl_hton##x((uint##x##_t)num); \
+	return q - p; \
+}
+
+#define cl_hton8(x) (x)
+
+UNPACK_FUNC(net,8);
+UNPACK_FUNC(net,16);
+UNPACK_FUNC(net,32);
+UNPACK_FUNC(net,64);
+
+static int unpack_string(char *p, uint8_t *buf, unsigned len)
+{
+	char *q = p;
+	char delim = ' ';
+	if (*q == '\'' || *q == '\"')
+		delim = *q++;
+	while (--len && *q && *q != delim)
+		*buf++ = *q++;
+	*buf = '\0';
+	if (*q == delim && delim != ' ')
+		q++;
+	return q - p;
+}
+
+static int unpack_string64(char *p, uint8_t *buf)
+{
+	return unpack_string(p, buf, 64);
+}
+
+#define PARSE_AHEAD(p, x, name, val_ptr) { int _ret; \
+	p = strstr(p, name); \
+	if (!p) { \
+		osm_log(&p_osm->log, OSM_LOG_ERROR, \
+			"PARSE ERROR: %s:%u: cannot find \"%s\" string\n", \
+			file_name, lineno, (name)); \
+		ret = -2; \
+		goto _error; \
+	} \
+	p += strlen(name); \
+	_ret = unpack_##x(p, (val_ptr)); \
+	if (_ret < 0) { \
+		osm_log(&p_osm->log, OSM_LOG_ERROR, \
+			"PARSE ERROR: %s:%u: cannot parse "#x" value " \
+			"after \"%s\"\n", file_name, lineno, (name)); \
+		ret = _ret; \
+		goto _error; \
+	} \
+	p += _ret; \
+}
+
+int osm_sa_db_file_load(osm_opensm_t *p_osm)
+{
+	char line[1024];
+	char *file_name;
+	FILE *file;
+	int ret = 0;
+	osm_mgrp_t *p_mgrp = NULL;
+	unsigned rereg_clients = 0;
+	unsigned lineno;
+
+	file_name = p_osm->subn.opt.sa_db_file;
+	if (!file_name) {
+		osm_log(&p_osm->log, OSM_LOG_VERBOSE,
+			"osm_sa_db_file_load: sa db file name is not "
+			"specifed. Skip restore\n");
+		return 0;
+	}
+
+	file = fopen(file_name, "r");
+	if (!file) {
+		osm_log(&p_osm->log, OSM_LOG_ERROR|OSM_LOG_SYS,
+			"osm_sa_db_file_load: ERR 0000: "
+			"cannot open sa db file \'%s\'. "
+			"Skip restoring\n", file_name);
+		return -1;
+	}
+
+	lineno = 0;
+
+	while (fgets(line, sizeof(line) - 1, file) != NULL) {
+		char *p;
+		uint8_t val;
+
+		lineno++;
+
+		p = line;
+		while (isspace(*p))
+			p++;
+
+		if (*p == '#')
+			continue;
+
+		if (!strncmp(p, "MC Group", 8)) {
+			ib_member_rec_t mcm_rec;
+			ib_net16_t mlid;
+			unsigned well_known = 0;
+
+			p_mgrp = NULL;
+			memset(&mcm_rec, 0, sizeof(mcm_rec));
+
+			PARSE_AHEAD(p, net16, " 0x", &mlid);
+			if(strstr(p, "well known"))
+				well_known = 1;
+			PARSE_AHEAD(p, net64, " mgid=0x",
+				    &mcm_rec.mgid.unicast.prefix);
+			PARSE_AHEAD(p, net64, ":0x",
+				    &mcm_rec.mgid.unicast.interface_id);
+			PARSE_AHEAD(p, net64, " port_gid=0x",
+				    &mcm_rec.port_gid.unicast.prefix);
+			PARSE_AHEAD(p, net64, ":0x",
+				    &mcm_rec.port_gid.unicast.interface_id);
+			PARSE_AHEAD(p, net32, " qkey=0x", &mcm_rec.qkey);
+			PARSE_AHEAD(p, net16, " mlid=0x", &mcm_rec.mlid);
+			PARSE_AHEAD(p, net8, " mtu=0x", &mcm_rec.mtu);
+			PARSE_AHEAD(p, net8, " tclass=0x", &mcm_rec.tclass);
+			PARSE_AHEAD(p, net16, " pkey=0x", &mcm_rec.pkey);
+			PARSE_AHEAD(p, net8, " rate=0x", &mcm_rec.rate);
+			PARSE_AHEAD(p, net8, " pkt_life=0x", &mcm_rec.pkt_life);
+			PARSE_AHEAD(p, net32, " sl_flow_hop=0x",
+				    &mcm_rec.sl_flow_hop);
+			PARSE_AHEAD(p, net8, " scope_state=0x",
+				    &mcm_rec.scope_state);
+			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
+			mcm_rec.proxy_join = val;
+
+			p_mgrp = load_mcgroup(p_osm, mlid, &mcm_rec,
+					      well_known);
+			if (!p_mgrp)
+				rereg_clients = 1;
+		}
+		else if (p_mgrp && !strncmp(p, "mcm_port", 8)) {
+			ib_gid_t port_gid;
+			ib_net64_t guid;
+			uint8_t scope_state;
+			boolean_t proxy_join;
+
+			PARSE_AHEAD(p, net64, " port_gid=0x",
+				    &port_gid.unicast.prefix);
+			PARSE_AHEAD(p, net64, ":0x",
+				    &port_gid.unicast.interface_id);
+			PARSE_AHEAD(p, net8, " scope_state=0x", &scope_state);
+			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
+			proxy_join = val;
+
+			guid = port_gid.unicast.interface_id;
+			if (cl_qmap_get(&p_mgrp->mcm_port_tbl,
+					port_gid.unicast.interface_id) ==
+				cl_qmap_end(&p_mgrp->mcm_port_tbl))
+				osm_mgrp_add_port(p_mgrp, &port_gid,
+						  scope_state, proxy_join);
+		}
+		else if (!strncmp(p, "Service Record:", 15)) {
+			ib_service_record_t s_rec;
+			uint32_t modified_time, lease_period;
+
+			p_mgrp = NULL;
+			memset(&s_rec, 0, sizeof(s_rec));
+
+			PARSE_AHEAD(p, net64, " id=0x", &s_rec.service_id);
+			PARSE_AHEAD(p, net64, " gid=0x",
+				    &s_rec.service_gid.unicast.prefix);
+			PARSE_AHEAD(p, net64, ":0x",
+				    &s_rec.service_gid.unicast.interface_id);
+			PARSE_AHEAD(p, net16, " pkey=0x", &s_rec.service_pkey);
+			PARSE_AHEAD(p, net32, " lease=0x", &s_rec.service_lease);
+			PARSE_AHEAD(p, net64, " key=0x",
+				    (ib_net64_t *)(&s_rec.service_key[0]));
+			PARSE_AHEAD(p, net64, ":0x",
+				    (ib_net64_t *)(&s_rec.service_key[8]));
+			PARSE_AHEAD(p, string64, " name=", s_rec.service_name);
+			PARSE_AHEAD(p, net64, " data8=0x",
+				    (ib_net64_t *)(&s_rec.service_data8[0]));
+			PARSE_AHEAD(p, net64, ":0x",
+				    (ib_net64_t *)(&s_rec.service_data8[8]));
+			PARSE_AHEAD(p, net64, " data16=0x",
+				    (ib_net64_t *)(&s_rec.service_data16[0]));
+			PARSE_AHEAD(p, net64, ":0x",
+				    (ib_net64_t *)(&s_rec.service_data16[4]));
+			PARSE_AHEAD(p, net64, " data32=0x",
+				    (ib_net64_t *)(&s_rec.service_data32[0]));
+			PARSE_AHEAD(p, net64, ":0x",
+				    (ib_net64_t *)(&s_rec.service_data32[2]));
+			PARSE_AHEAD(p, net64, " data64=0x", &s_rec.service_data64[0]);
+			PARSE_AHEAD(p, net64, ":0x", &s_rec.service_data64[1]);
+			PARSE_AHEAD(p, net32, " modified_time=0x",
+				    &modified_time);
+			PARSE_AHEAD(p, net32, " lease_period=0x",
+				    &lease_period);
+
+			if (load_svcr(p_osm, &s_rec, cl_ntoh32(modified_time),
+				      cl_ntoh32(lease_period)))
+				rereg_clients = 1;
+		}
+		else if (!strncmp(p, "InformInfo Record:", 18)) {
+			ib_inform_info_record_t i_rec;
+			osm_mad_addr_t rep_addr;
+
+			p_mgrp = NULL;
+			memset(&i_rec, 0, sizeof(i_rec));
+			memset(&rep_addr, 0, sizeof(rep_addr));
+
+			PARSE_AHEAD(p, net64, " subscriber_gid=0x",
+				    &i_rec.subscriber_gid.unicast.prefix);
+			PARSE_AHEAD(p, net64, ":0x",
+				    &i_rec.subscriber_gid.unicast.interface_id);
+			PARSE_AHEAD(p, net16, " subscriber_enum=0x",
+				    &i_rec.subscriber_enum);
+			PARSE_AHEAD(p, net64, " gid=0x",
+				    &i_rec.inform_info.gid.unicast.prefix);
+			PARSE_AHEAD(p, net64, ":0x",
+				    &i_rec.inform_info.gid.unicast.interface_id);
+			PARSE_AHEAD(p, net16, " lid_range_begin=0x",
+				    &i_rec.inform_info.lid_range_begin);
+			PARSE_AHEAD(p, net16, " lid_range_end=0x",
+				    &i_rec.inform_info.lid_range_end);
+			PARSE_AHEAD(p, net8, " is_generic=0x",
+				    &i_rec.inform_info.is_generic);
+			PARSE_AHEAD(p, net8, " subscribe=0x",
+				    &i_rec.inform_info.subscribe);
+			PARSE_AHEAD(p, net16, " trap_type=0x",
+				    &i_rec.inform_info.trap_type);
+			PARSE_AHEAD(p, net16, " trap_num=0x",
+				    &i_rec.inform_info.g_or_v.generic.trap_num);
+			PARSE_AHEAD(p, net32, " qpn_resp_time_val=0x",
+				    &i_rec.inform_info.g_or_v.generic.qpn_resp_time_val);
+			PARSE_AHEAD(p, net32, " node_type=0x",
+				    (uint32_t *)&i_rec.inform_info.g_or_v.generic.reserved2);
+
+			PARSE_AHEAD(p, net16, " rep_addr: lid=0x",
+				    &rep_addr.dest_lid);
+			PARSE_AHEAD(p, net8, " path_bits=0x",
+				    &rep_addr.path_bits);
+			PARSE_AHEAD(p, net8, " static_rate=0x",
+				    &rep_addr.static_rate);
+			PARSE_AHEAD(p, net32, " remote_qp=0x",
+				    &rep_addr.addr_type.gsi.remote_qp);
+			PARSE_AHEAD(p, net32, " remote_qkey=0x",
+				    &rep_addr.addr_type.gsi.remote_qkey);
+			PARSE_AHEAD(p, net16, " pkey=0x",
+				    &rep_addr.addr_type.gsi.pkey);
+			PARSE_AHEAD(p, net8, " sl=0x",
+				    &rep_addr.addr_type.gsi.service_level);
+
+			if (load_infr(p_osm, &i_rec, &rep_addr))
+				rereg_clients = 1;
+		}
+	}
+
+	if (!rereg_clients)
+		p_osm->subn.opt.no_clients_rereg = TRUE;
+
+  _error:
+	fclose(file);
+	return ret;
+}
diff --git a/osm/opensm/osm_sa_mcmember_record.c b/osm/opensm/osm_sa_mcmember_record.c
index bd52c77..f7f879b 100644
--- a/osm/opensm/osm_sa_mcmember_record.c
+++ b/osm/opensm/osm_sa_mcmember_record.c
@@ -291,7 +291,7 @@ available mlids.
 **********************************************************************/
 static ib_net16_t
 __get_new_mlid(
-  IN osm_mcmr_recv_t* const p_rcv)
+  IN osm_mcmr_recv_t* const p_rcv, ib_net16_t requested_mlid)
 {
   osm_subn_t   *p_subn = p_rcv->p_subn;
   osm_mgrp_t   *p_mgrp;
@@ -301,7 +301,15 @@ __get_new_mlid(
   uint16_t      max_num_mlids;
 
   OSM_LOG_ENTER(p_rcv->p_log, __get_new_mlid);
- 
+
+  if (requested_mlid && cl_ntoh16(requested_mlid) >= IB_LID_MCAST_START_HO &&
+      cl_ntoh16(requested_mlid) < p_subn->max_multicast_lid_ho &&
+      cl_qmap_get(&p_subn->mgrp_mlid_tbl, requested_mlid) ==
+      cl_qmap_end(&p_subn->mgrp_mlid_tbl) ) {
+    mlid = cl_ntoh16(requested_mlid);
+    goto Exit;
+  }
+
   /* If MCGroups table empty, first return the min mlid */
   p_mgrp = (osm_mgrp_t*)cl_qmap_head( &p_subn->mgrp_mlid_tbl );
   if (p_mgrp == (osm_mgrp_t*)cl_qmap_end( &p_subn->mgrp_mlid_tbl ))
@@ -1249,7 +1257,7 @@ osm_mcmr_rcv_create_new_mgrp(
     we allocate a new mlid number before we might use it
     for MGID ...
   */
-  mlid = __get_new_mlid(p_rcv);
+  mlid = __get_new_mlid(p_rcv, mcm_rec.mlid);
   if ( mlid == 0 )
   {
     osm_log( p_rcv->p_log, OSM_LOG_ERROR,
diff --git a/osm/opensm/osm_state_mgr.c b/osm/opensm/osm_state_mgr.c
index 993b7eb..b830a9c 100644
--- a/osm/opensm/osm_state_mgr.c
+++ b/osm/opensm/osm_state_mgr.c
@@ -2220,6 +2220,11 @@ osm_state_mgr_process(
             /* the returned signal is always DONE */
             signal = osm_qos_setup(p_mgr->p_subn->p_osm);
 
+            /* try to restore SA DB (this should be before lid_mgr
+               because we may want to disable clients reregistration
+               when SA DB is restored) */
+            osm_sa_db_file_load(p_mgr->p_subn->p_osm);
+
             break;
 
          default:
@@ -2806,6 +2811,9 @@ osm_state_mgr_process(
                osm_topology_file_create( p_mgr );
                __osm_state_mgr_report( p_mgr );
                __osm_state_mgr_up_msg( p_mgr );
+
+	       if( osm_log_is_active(p_mgr->p_log, OSM_LOG_VERBOSE) )
+                  osm_sa_db_file_dump(p_mgr->p_subn->p_osm);
             }
             p_mgr->state = OSM_SM_STATE_PROCESS_REQUEST;
             signal = OSM_SIGNAL_IDLE_TIME_PROCESS;
diff --git a/osm/opensm/osm_subnet.c b/osm/opensm/osm_subnet.c
index e53aad4..56963c4 100644
--- a/osm/opensm/osm_subnet.c
+++ b/osm/opensm/osm_subnet.c
@@ -495,8 +495,10 @@ osm_subn_set_default_opt(
   p_opt->lid_matrix_dump_file = NULL;
   p_opt->ucast_dump_file = NULL;
   p_opt->updn_guid_file = NULL;
+  p_opt->sa_db_file = NULL;
   p_opt->exit_on_fatal = TRUE;
   p_opt->enable_quirks = FALSE;
+  p_opt->no_clients_rereg = FALSE;
   subn_set_default_qos_options(&p_opt->qos_options);
   subn_set_default_qos_options(&p_opt->qos_ca_options);
   subn_set_default_qos_options(&p_opt->qos_sw0_options);
@@ -972,6 +974,10 @@ osm_subn_parse_conf_file(
         "updn_guid_file",
         p_key, p_val, &p_opts->updn_guid_file);
 
+      __osm_subn_opts_unpack_charp(
+        "sa_db_file",
+        p_key, p_val, &p_opts->sa_db_file);
+
       __osm_subn_opts_unpack_boolean(
         "exit_on_fatal",
         p_key, p_val, &p_opts->exit_on_fatal);
@@ -1157,6 +1163,11 @@ osm_subn_write_conf_file(
              "# One guid in each line\n"
              "updn_guid_file %s\n\n",
              p_opts->updn_guid_file);
+  if (p_opts->sa_db_file)
+    fprintf( opts_file,
+             "# SA database file name\n"
+             "sa_db_file %s\n\n",
+             p_opts->sa_db_file);
   
   fprintf( 
     opts_file,    
-- 
1.4.4.g031c-dirty





More information about the general mailing list