/*
* Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
* Copyright (c) 2002-2014 Mellanox Technologies LTD. All rights reserved.
* Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
* Copyright (c) 2008 Xsigo Systems 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.
*
*/
/*
* Abstract:
* Implementation of osm_sa_t.
* This object represents the Subnet Administration object.
* This object is part of the opensm family of objects.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <complib/cl_qmap.h>
#include <complib/cl_passivelock.h>
#include <complib/cl_debug.h>
#include <iba/ib_types.h>
#include <opensm/osm_file_ids.h>
#define FILE_ID OSM_FILE_SA_C
#include <opensm/osm_sa.h>
#include <opensm/osm_madw.h>
#include <opensm/osm_log.h>
#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>
#include <opensm/osm_guid.h>
#include <opensm/osm_helper.h>
#include <vendor/osm_vendor_api.h>
#define OSM_SA_INITIAL_TID_VALUE 0xabc
extern void osm_cpi_rcv_process(IN void *context, IN void *data);
extern void osm_gir_rcv_process(IN void *context, IN void *data);
extern void osm_infr_rcv_process(IN void *context, IN void *data);
extern void osm_infir_rcv_process(IN void *context, IN void *data);
extern void osm_lftr_rcv_process(IN void *context, IN void *data);
extern void osm_lr_rcv_process(IN void *context, IN void *data);
extern void osm_mcmr_rcv_process(IN void *context, IN void *data);
extern void osm_mftr_rcv_process(IN void *context, IN void *data);
extern void osm_mpr_rcv_process(IN void *context, IN void *data);
extern void osm_nr_rcv_process(IN void *context, IN void *data);
extern void osm_pr_rcv_process(IN void *context, IN void *data);
extern void osm_pkey_rec_rcv_process(IN void *context, IN void *data);
extern void osm_pir_rcv_process(IN void *context, IN void *data);
extern void osm_sr_rcv_process(IN void *context, IN void *data);
extern void osm_slvl_rec_rcv_process(IN void *context, IN void *data);
extern void osm_smir_rcv_process(IN void *context, IN void *data);
extern void osm_sir_rcv_process(IN void *context, IN void *data);
extern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data);
extern void osm_sr_rcv_lease_cb(IN void *context);
void osm_sa_construct(IN osm_sa_t * p_sa)
{
memset(p_sa, 0, sizeof(*p_sa));
p_sa->state = OSM_SA_STATE_INIT;
p_sa->sa_trans_id = OSM_SA_INITIAL_TID_VALUE;
cl_timer_construct(&p_sa->sr_timer);
}
void osm_sa_shutdown(IN osm_sa_t * p_sa)
{
OSM_LOG_ENTER(p_sa->p_log);
cl_timer_stop(&p_sa->sr_timer);
/* unbind from the mad service */
osm_sa_mad_ctrl_unbind(&p_sa->mad_ctrl);
/* remove any registered dispatcher message */
cl_disp_unregister(p_sa->nr_disp_h);
cl_disp_unregister(p_sa->pir_disp_h);
cl_disp_unregister(p_sa->gir_disp_h);
cl_disp_unregister(p_sa->lr_disp_h);
cl_disp_unregister(p_sa->pr_disp_h);
#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
cl_disp_unregister(p_sa->mpr_disp_h);
#endif
cl_disp_unregister(p_sa->smir_disp_h);
cl_disp_unregister(p_sa->mcmr_disp_h);
cl_disp_unregister(p_sa->sr_disp_h);
cl_disp_unregister(p_sa->infr_disp_h);
cl_disp_unregister(p_sa->infir_disp_h);
cl_disp_unregister(p_sa->vlarb_disp_h);
cl_disp_unregister(p_sa->slvl_disp_h);
cl_disp_unregister(p_sa->pkey_disp_h);
cl_disp_unregister(p_sa->lft_disp_h);
cl_disp_unregister(p_sa->sir_disp_h);
cl_disp_unregister(p_sa->mft_disp_h);
if (p_sa->p_set_disp) {
cl_disp_unregister(p_sa->mcmr_set_disp_h);
cl_disp_unregister(p_sa->infr_set_disp_h);
cl_disp_unregister(p_sa->sr_set_disp_h);
cl_disp_unregister(p_sa->gir_set_disp_h);
}
osm_sa_mad_ctrl_destroy(&p_sa->mad_ctrl);
OSM_LOG_EXIT(p_sa->p_log);
}
void osm_sa_destroy(IN osm_sa_t * p_sa)
{
OSM_LOG_ENTER(p_sa->p_log);
p_sa->state = OSM_SA_STATE_INIT;
cl_timer_destroy(&p_sa->sr_timer);
OSM_LOG_EXIT(p_sa->p_log);
}
ib_api_status_t osm_sa_init(IN osm_sm_t * p_sm, IN osm_sa_t * p_sa,
IN osm_subn_t * p_subn, IN osm_vendor_t * p_vendor,
IN osm_mad_pool_t * p_mad_pool,
IN osm_log_t * p_log, IN osm_stats_t * p_stats,
IN cl_dispatcher_t * p_disp,
IN cl_dispatcher_t * p_set_disp,
IN cl_plock_t * p_lock)
{
ib_api_status_t status;
OSM_LOG_ENTER(p_log);
p_sa->sm = p_sm;
p_sa->p_subn = p_subn;
p_sa->p_vendor = p_vendor;
p_sa->p_mad_pool = p_mad_pool;
p_sa->p_log = p_log;
p_sa->p_disp = p_disp;
p_sa->p_set_disp = p_set_disp;
p_sa->p_lock = p_lock;
p_sa->state = OSM_SA_STATE_READY;
status = osm_sa_mad_ctrl_init(&p_sa->mad_ctrl, p_sa, p_sa->p_mad_pool,
p_sa->p_vendor, p_subn, p_log, p_stats,
p_disp, p_set_disp);
if (status != IB_SUCCESS)
goto Exit;
status = cl_timer_init(&p_sa->sr_timer, osm_sr_rcv_lease_cb, p_sa);
if (status != IB_SUCCESS)
goto Exit;
status = IB_INSUFFICIENT_RESOURCES;
p_sa->cpi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_CLASS_PORT_INFO,
osm_cpi_rcv_process, p_sa);
if (p_sa->cpi_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->nr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_RECORD,
osm_nr_rcv_process, p_sa);
if (p_sa->nr_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->pir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORTINFO_RECORD,
osm_pir_rcv_process, p_sa);
if (p_sa->pir_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->gir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_GUIDINFO_RECORD,
osm_gir_rcv_process, p_sa);
if (p_sa->gir_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->lr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LINK_RECORD,
osm_lr_rcv_process, p_sa);
if (p_sa->lr_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->pr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PATH_RECORD,
osm_pr_rcv_process, p_sa);
if (p_sa->pr_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
p_sa->mpr_disp_h =
cl_disp_register(p_disp, OSM_MSG_MAD_MULTIPATH_RECORD,
osm_mpr_rcv_process, p_sa);
if (p_sa->mpr_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
#endif
p_sa->smir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SMINFO_RECORD,
osm_smir_rcv_process, p_sa);
if (p_sa->smir_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->mcmr_disp_h =
cl_disp_register(p_disp, OSM_MSG_MAD_MCMEMBER_RECORD,
osm_mcmr_rcv_process, p_sa);
if (p_sa->mcmr_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->sr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SERVICE_RECORD,
osm_sr_rcv_process, p_sa);
if (p_sa->sr_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->infr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO,
osm_infr_rcv_process, p_sa);
if (p_sa->infr_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->infir_disp_h =
cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO_RECORD,
osm_infir_rcv_process, p_sa);
if (p_sa->infir_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->vlarb_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB_RECORD,
osm_vlarb_rec_rcv_process, p_sa);
if (p_sa->vlarb_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->slvl_disp_h =
cl_disp_register(p_disp, OSM_MSG_MAD_SLVL_TBL_RECORD,
osm_slvl_rec_rcv_process, p_sa);
if (p_sa->slvl_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->pkey_disp_h =
cl_disp_register(p_disp, OSM_MSG_MAD_PKEY_TBL_RECORD,
osm_pkey_rec_rcv_process, p_sa);
if (p_sa->pkey_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT_RECORD,
osm_lftr_rcv_process, p_sa);
if (p_sa->lft_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->sir_disp_h =
cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO_RECORD,
osm_sir_rcv_process, p_sa);
if (p_sa->sir_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT_RECORD,
osm_mftr_rcv_process, p_sa);
if (p_sa->mft_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
/*
* When p_set_disp is defined, it means that we use different dispatcher
* for SA Set requests, and we need to register handlers for it.
*/
if (p_set_disp) {
p_sa->gir_set_disp_h =
cl_disp_register(p_set_disp, OSM_MSG_MAD_GUIDINFO_RECORD,
osm_gir_rcv_process, p_sa);
if (p_sa->gir_set_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->mcmr_set_disp_h =
cl_disp_register(p_set_disp, OSM_MSG_MAD_MCMEMBER_RECORD,
osm_mcmr_rcv_process, p_sa);
if (p_sa->mcmr_set_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->sr_set_disp_h =
cl_disp_register(p_set_disp, OSM_MSG_MAD_SERVICE_RECORD,
osm_sr_rcv_process, p_sa);
if (p_sa->sr_set_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
p_sa->infr_set_disp_h =
cl_disp_register(p_set_disp, OSM_MSG_MAD_INFORM_INFO,
osm_infr_rcv_process, p_sa);
if (p_sa->infr_set_disp_h == CL_DISP_INVALID_HANDLE)
goto Exit;
}
status = IB_SUCCESS;
Exit:
OSM_LOG_EXIT(p_log);
return status;
}
ib_api_status_t osm_sa_bind(IN osm_sa_t * p_sa, IN ib_net64_t port_guid)
{
ib_api_status_t status;
OSM_LOG_ENTER(p_sa->p_log);
status = osm_sa_mad_ctrl_bind(&p_sa->mad_ctrl, port_guid);
if (status != IB_SUCCESS) {
OSM_LOG(p_sa->p_log, OSM_LOG_ERROR, "ERR 4C03: "
"SA MAD Controller bind failed (%s)\n",
ib_get_err_str(status));
}
OSM_LOG_EXIT(p_sa->p_log);
return status;
}
ib_api_status_t osm_sa_send(osm_sa_t *sa, IN osm_madw_t * p_madw,
IN boolean_t resp_expected)
{
ib_api_status_t status;
cl_atomic_inc(&sa->p_subn->p_osm->stats.sa_mads_sent);
status = osm_vendor_send(p_madw->h_bind, p_madw, resp_expected);
if (status != IB_SUCCESS) {
cl_atomic_dec(&sa->p_subn->p_osm->stats.sa_mads_sent);
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C04: "
"osm_vendor_send failed, status = %s\n",
ib_get_err_str(status));
}
return status;
}
void osm_sa_send_error(IN osm_sa_t * sa, IN const osm_madw_t * p_madw,
IN ib_net16_t sa_status)
{
osm_madw_t *p_resp_madw;
ib_sa_mad_t *p_resp_sa_mad;
ib_sa_mad_t *p_sa_mad;
OSM_LOG_ENTER(sa->p_log);
/* avoid races - if we are exiting - exit */
if (osm_exit_flag) {
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
"Ignoring requested send after exit\n");
goto Exit;
}
p_resp_madw = osm_mad_pool_get(sa->p_mad_pool,
p_madw->h_bind, MAD_BLOCK_SIZE,
&p_madw->mad_addr);
if (p_resp_madw == NULL) {
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C07: "
"Unable to acquire response MAD\n");
goto Exit;
}
p_resp_sa_mad = osm_madw_get_sa_mad_ptr(p_resp_madw);
p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
/* Copy the MAD header back into the response mad */
*p_resp_sa_mad = *p_sa_mad;
p_resp_sa_mad->status = sa_status;
if (p_resp_sa_mad->method == IB_MAD_METHOD_SET)
p_resp_sa_mad->method = IB_MAD_METHOD_GET;
else if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE)
p_resp_sa_mad->attr_offset = 0;
p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
/*
* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884)
*/
p_resp_sa_mad->sm_key = 0;
/*
* o15-0.2.7 - The PathRecord Attribute ID shall be used in
* the response (to a SubnAdmGetMulti(MultiPathRecord)
*/
if (p_resp_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD)
p_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_FRAMES))
osm_dump_sa_mad_v2(sa->p_log, p_resp_sa_mad, FILE_ID, OSM_LOG_FRAMES);
osm_sa_send(sa, p_resp_madw, FALSE);
Exit:
OSM_LOG_EXIT(sa->p_log);
}
void osm_sa_respond(osm_sa_t *sa, osm_madw_t *madw, size_t attr_size,
cl_qlist_t *list)
{
cl_list_item_t *item;
osm_madw_t *resp_madw;
ib_sa_mad_t *sa_mad, *resp_sa_mad;
unsigned num_rec, i;
#ifndef VENDOR_RMPP_SUPPORT
unsigned trim_num_rec;
#endif
unsigned char *p;
sa_mad = osm_madw_get_sa_mad_ptr(madw);
num_rec = cl_qlist_count(list);
/*
* C15-0.1.30:
* If we do a SubnAdmGet and got more than one record it is an error!
*/
if (sa_mad->method == IB_MAD_METHOD_GET && num_rec > 1) {
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C05: "
"Got %u records for SubnAdmGet(%s) comp_mask 0x%016" PRIx64
" from requester LID %u\n",
num_rec, ib_get_sa_attr_str(sa_mad->attr_id),
cl_ntoh64(sa_mad->comp_mask),
cl_ntoh16(madw->mad_addr.dest_lid));
osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_TOO_MANY_RECORDS);
goto Exit;
}
#ifndef VENDOR_RMPP_SUPPORT
trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / attr_size;
if (trim_num_rec < num_rec) {
OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
"Number of records:%u trimmed to:%u to fit in one MAD\n",
num_rec, trim_num_rec);
num_rec = trim_num_rec;
}
#endif
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Returning %u records\n", num_rec);
if (sa_mad->method == IB_MAD_METHOD_GET && num_rec == 0) {
osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RECORDS);
goto Exit;
}
/*
* Get a MAD to reply. Address of Mad is in the received mad_wrapper
*/
resp_madw = osm_mad_pool_get(sa->p_mad_pool, madw->h_bind,
num_rec * attr_size + IB_SA_MAD_HDR_SIZE,
&madw->mad_addr);
if (!resp_madw) {
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C06: "
"osm_mad_pool_get failed\n");
osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RESOURCES);
goto Exit;
}
resp_sa_mad = osm_madw_get_sa_mad_ptr(resp_madw);
/*
Copy the MAD header back into the response mad.
Set the 'R' bit and the payload length,
Then copy all records from the list into the response payload.
*/
memcpy(resp_sa_mad, sa_mad, IB_SA_MAD_HDR_SIZE);
if (resp_sa_mad->method == IB_MAD_METHOD_SET)
resp_sa_mad->method = IB_MAD_METHOD_GET;
resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
/* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
resp_sa_mad->sm_key = 0;
/* Fill in the offset (paylen will be done by the rmpp SAR) */
resp_sa_mad->attr_offset = num_rec ? ib_get_attr_offset(attr_size) : 0;
p = ib_sa_mad_get_payload_ptr(resp_sa_mad);
#ifndef VENDOR_RMPP_SUPPORT
/* we support only one packet RMPP - so we will set the first and
last flags for gettable */
if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) {
resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;
resp_sa_mad->rmpp_flags =
IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST |
IB_RMPP_FLAG_ACTIVE;
}
#else
/* forcefully define the packet as RMPP one */
if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
#endif
for (i = 0; i < num_rec; i++) {
item = cl_qlist_remove_head(list);
memcpy(p, ((osm_sa_item_t *)item)->resp.data, attr_size);
p += attr_size;
free(item);
}
osm_dump_sa_mad_v2(sa->p_log, resp_sa_mad, FILE_ID, OSM_LOG_FRAMES);
osm_sa_send(sa, resp_madw, FALSE);
Exit:
/* need to set the mem free ... */
item = cl_qlist_remove_head(list);
while (item != cl_qlist_end(list)) {
free(item);
item = cl_qlist_remove_head(list);
}
}
/*
* 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];
char path_tmp[1032];
FILE *file;
int fd, status = 0;
snprintf(path, sizeof(path), "%s/%s",
p_osm->subn.opt.dump_files_dir, file_name);
snprintf(path_tmp, sizeof(path_tmp), "%s.tmp", path);
file = fopen(path_tmp, "w");
if (!file) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C01: "
"cannot open file \'%s\': %s\n",
path_tmp, strerror(errno));
return -1;
}
if (chmod(path_tmp, S_IRUSR | S_IWUSR)) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0C: "
"cannot change access permissions of file "
"\'%s\' : %s\n",
path_tmp, strerror(errno));
fclose(file);
return -1;
}
dump_func(p_osm, file);
if (p_osm->subn.opt.fsync_high_avail_files) {
if (fflush(file) == 0) {
fd = fileno(file);
if (fd != -1) {
if (fsync(fd) == -1)
OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
"ERR 4C08: fsync() failed (%s) for %s\n",
strerror(errno), path_tmp);
} else
OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C09: "
"fileno() failed for %s\n", path_tmp);
} else
OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0A: "
"fflush() failed (%s) for %s\n",
strerror(errno), path_tmp);
}
fclose(file);
status = rename(path_tmp, path);
if (status) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0B: "
"Failed to rename file:%s (err:%s)\n",
path_tmp, strerror(errno));
}
return status;
}
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_alias_guid_t *p_mcm_alias_guid = (osm_mcm_alias_guid_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_alias_guid->port_gid.unicast.prefix),
cl_ntoh64(p_mcm_alias_guid->port_gid.unicast.interface_id),
p_mcm_alias_guid->scope_state, p_mcm_alias_guid->proxy_join);
}
static void sa_dump_one_mgrp(osm_mgrp_t *p_mgrp, 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;
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_alias_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_ix=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_prod_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),
p_infr->report_addr.addr_type.gsi.pkey_ix,
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_one_port_guidinfo(cl_map_item_t * p_map_item, void *cxt)
{
FILE *file = ((struct opensm_dump_context *)cxt)->file;
osm_port_t *p_port = (osm_port_t *) p_map_item;
uint32_t max_block;
int block_num;
if (!p_port->p_physp->p_guids)
return;
max_block = (p_port->p_physp->port_info.guid_cap + GUID_TABLE_MAX_ENTRIES - 1) /
GUID_TABLE_MAX_ENTRIES;
for (block_num = 0; block_num < max_block; block_num++) {
fprintf(file, "GUIDInfo Record:"
" base_guid=0x%016" PRIx64 " lid=0x%04x block_num=0x%x"
" guid0=0x%016" PRIx64 " guid1=0x%016" PRIx64
" guid2=0x%016" PRIx64 " guid3=0x%016" PRIx64
" guid4=0x%016" PRIx64 " guid5=0x%016" PRIx64
" guid6=0x%016" PRIx64 " guid7=0x%016" PRIx64
"\n\n",
cl_ntoh64((*p_port->p_physp->p_guids)[0]),
cl_ntoh16(osm_port_get_base_lid(p_port)), block_num,
cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES]),
cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 1]),
cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 2]),
cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 3]),
cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 4]),
cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 5]),
cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 6]),
cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 7]));
}
}
static void sa_dump_all_sa(osm_opensm_t * p_osm, FILE * file)
{
struct opensm_dump_context dump_context;
osm_mgrp_t *p_mgrp;
dump_context.p_osm = p_osm;
dump_context.file = file;
OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump guidinfo\n");
cl_qmap_apply_func(&p_osm->subn.port_guid_tbl,
sa_dump_one_port_guidinfo, &dump_context);
OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump multicast\n");
for (p_mgrp = (osm_mgrp_t *) cl_fmap_head(&p_osm->subn.mgrp_mgid_tbl);
p_mgrp != (osm_mgrp_t *) cl_fmap_end(&p_osm->subn.mgrp_mgid_tbl);
p_mgrp = (osm_mgrp_t *) cl_fmap_next(&p_mgrp->map_item))
sa_dump_one_mgrp(p_mgrp, &dump_context);
OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "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, "Dump services\n");
cl_qlist_apply_func(&p_osm->subn.sa_sr_list,
sa_dump_one_service, &dump_context);
}
int osm_sa_db_file_dump(osm_opensm_t * p_osm)
{
int res = 1;
cl_plock_acquire(&p_osm->lock);
if (p_osm->sa.dirty) {
res = opensm_dump_to_file(
p_osm, "opensm-sa.dump", sa_dump_all_sa);
if (!res)
p_osm->sa.dirty = FALSE;
}
cl_plock_release(&p_osm->lock);
return res;
}
/*
* SA DB Loader
*/
static osm_mgrp_t *load_mcgroup(osm_opensm_t * p_osm, ib_net16_t mlid,
ib_member_rec_t * p_mcm_rec)
{
ib_net64_t comp_mask;
osm_mgrp_t *p_mgrp;
cl_plock_excl_acquire(&p_osm->lock);
p_mgrp = osm_get_mgrp_by_mgid(&p_osm->subn, &p_mcm_rec->mgid);
if (p_mgrp) {
if (p_mgrp->mlid == mlid) {
OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
"mgrp %04x is already here.", cl_ntoh16(mlid));
goto _out;
}
OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
"mlid %04x is already used by another MC group. Will "
"request clients reregistration.\n", cl_ntoh16(mlid));
p_mgrp = NULL;
goto _out;
}
comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL
| IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL;
if (!(p_mgrp = osm_mcmr_rcv_find_or_create_new_mgrp(&p_osm->sa,
comp_mask,
p_mcm_rec)) ||
p_mgrp->mlid != mlid) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
"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;
}
_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,
"ServiceRecord already exists\n");
goto _out;
}
if (!(p_svcr = osm_svcr_new(sr))) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
"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, "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_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.sa = &p_osm->sa;
/* other possible way to restore mad_addr partially is
to extract qpn from InformInfo 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,
"InformInfo Record already exists\n");
goto _out;
}
if (!(p_infr = osm_infr_new(&infr))) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
"cannot allocate new infr struct\n");
ret = -1;
goto _out;
}
OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "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;
}
static int load_guidinfo(osm_opensm_t * p_osm, ib_net64_t base_guid,
ib_guidinfo_record_t *gir)
{
osm_port_t *p_port;
uint32_t max_block;
int i, ret = 0;
osm_alias_guid_t *p_alias_guid, *p_alias_guid_check;
cl_plock_excl_acquire(&p_osm->lock);
p_port = osm_get_port_by_guid(&p_osm->subn, base_guid);
if (!p_port)
goto _out;
if (!p_port->p_physp->p_guids) {
max_block = (p_port->p_physp->port_info.guid_cap + GUID_TABLE_MAX_ENTRIES - 1) /
GUID_TABLE_MAX_ENTRIES;
p_port->p_physp->p_guids = calloc(max_block * GUID_TABLE_MAX_ENTRIES,
sizeof(ib_net64_t));
if (!p_port->p_physp->p_guids) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
"cannot allocate GUID table for port "
"GUID 0x%" PRIx64 "\n",
cl_ntoh64(p_port->p_physp->port_guid));
goto _out;
}
}
for (i = 0; i < GUID_TABLE_MAX_ENTRIES; i++) {
if (!gir->guid_info.guid[i])
continue;
/* skip block 0 index 0 */
if (gir->block_num == 0 && i == 0)
continue;
if (gir->block_num * GUID_TABLE_MAX_ENTRIES + i >
p_port->p_physp->port_info.guid_cap)
break;
p_alias_guid = osm_alias_guid_new(gir->guid_info.guid[i],
p_port);
if (!p_alias_guid) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
"Alias guid %d memory allocation failed"
" for port GUID 0x%" PRIx64 "\n",
gir->block_num * GUID_TABLE_MAX_ENTRIES + i,
cl_ntoh64(p_port->p_physp->port_guid));
goto _out;
}
p_alias_guid_check =
(osm_alias_guid_t *) cl_qmap_insert(&p_osm->subn.alias_port_guid_tbl,
p_alias_guid->alias_guid,
&p_alias_guid->map_item);
if (p_alias_guid_check != p_alias_guid) {
/* alias GUID is a duplicate */
OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
"Duplicate alias port GUID 0x%" PRIx64
" index %d base port GUID 0x%" PRIx64 "\n",
cl_ntoh64(p_alias_guid->alias_guid),
gir->block_num * GUID_TABLE_MAX_ENTRIES + i,
cl_ntoh64(p_alias_guid->p_base_port->guid));
osm_alias_guid_delete(&p_alias_guid);
goto _out;
}
}
memcpy(&(*p_port->p_physp->p_guids)[gir->block_num * GUID_TABLE_MAX_ENTRIES],
&gir->guid_info, sizeof(ib_guid_info_t));
osm_queue_guidinfo(&p_osm->sa, p_port, gir->block_num);
_out:
cl_plock_release(&p_osm->lock);
return ret;
}
#define UNPACK_FUNC(name,x) \
static 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 (int)(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 (int)(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; \
}
static void sa_db_file_load_handle_mgrp(osm_opensm_t * p_osm,
osm_mgrp_t * p_mgrp)
{
/* decide whether to delete the mgrp object or not */
if (p_mgrp->full_members == 0 && !p_mgrp->well_known) {
OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
"Closing MC group 0x%016" PRIx64 ":0x%016" PRIx64
" - no full members were added to not well known "
"group\n",
cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix),
cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id));
osm_mgrp_cleanup(&p_osm->subn, p_mgrp);
}
}
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_next_mgrp = NULL;
osm_mgrp_t *p_prev_mgrp = NULL;
unsigned rereg_clients = 0;
unsigned lineno;
if (!p_osm->subn.first_time_master_sweep) {
OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
"Not first sweep - skip SA DB restore\n");
return 0;
}
file_name = p_osm->subn.opt.sa_db_file;
if (!file_name) {
OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
"sa db file name is not specified. Skip restore\n");
return 0;
}
file = fopen(file_name, "r");
if (!file) {
OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 4C02: "
"Can't open sa db file \'%s\'. Skip restoring\n",
file_name);
return -1;
}
OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
"Restoring SA DB from file \'%s\'\n",
file_name);
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;
p_next_mgrp = NULL;
memset(&mcm_rec, 0, sizeof(mcm_rec));
PARSE_AHEAD(p, net16, " 0x", &mlid);
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_next_mgrp = load_mcgroup(p_osm, mlid, &mcm_rec);
if (!p_next_mgrp)
rereg_clients = 1;
if (cl_ntoh16(mlid) > p_osm->sm.mlids_init_max)
p_osm->sm.mlids_init_max = cl_ntoh16(mlid);
} else if (p_next_mgrp && !strncmp(p, "mcm_port", 8)) {
ib_member_rec_t mcmr;
ib_net64_t guid;
osm_port_t *port;
boolean_t proxy;
PARSE_AHEAD(p, net64, " port_gid=0x",
&mcmr.port_gid.unicast.prefix);
PARSE_AHEAD(p, net64, ":0x",
&mcmr.port_gid.unicast.interface_id);
PARSE_AHEAD(p, net8, " scope_state=0x", &mcmr.scope_state);
PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
proxy = val;
guid = mcmr.port_gid.unicast.interface_id;
port = osm_get_port_by_alias_guid(&p_osm->subn, guid);
if (port &&
cl_qmap_get(&p_next_mgrp->mcm_port_tbl, guid) ==
cl_qmap_end(&p_next_mgrp->mcm_port_tbl) &&
!osm_mgrp_add_port(&p_osm->subn, &p_osm->log,
p_next_mgrp, port, &mcmr, proxy))
rereg_clients = 1;
} else if (!strncmp(p, "Service Record:", 15)) {
ib_service_record_t s_rec;
uint32_t modified_time, lease_period;
p_next_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;
ib_net16_t val16;
p_next_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_ix=0x", &val16);
rep_addr.addr_type.gsi.pkey_ix = cl_ntoh16(val16);
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;
} else if (!strncmp(p, "GUIDInfo Record:", 16)) {
ib_guidinfo_record_t gi_rec;
ib_net64_t base_guid;
p_next_mgrp = NULL;
memset(&gi_rec, 0, sizeof(gi_rec));
PARSE_AHEAD(p, net64, " base_guid=0x", &base_guid);
PARSE_AHEAD(p, net16, " lid=0x", &gi_rec.lid);
PARSE_AHEAD(p, net8, " block_num=0x",
&gi_rec.block_num);
PARSE_AHEAD(p, net64, " guid0=0x",
&gi_rec.guid_info.guid[0]);
PARSE_AHEAD(p, net64, " guid1=0x",
&gi_rec.guid_info.guid[1]);
PARSE_AHEAD(p, net64, " guid2=0x",
&gi_rec.guid_info.guid[2]);
PARSE_AHEAD(p, net64, " guid3=0x",
&gi_rec.guid_info.guid[3]);
PARSE_AHEAD(p, net64, " guid4=0x",
&gi_rec.guid_info.guid[4]);
PARSE_AHEAD(p, net64, " guid5=0x",
&gi_rec.guid_info.guid[5]);
PARSE_AHEAD(p, net64, " guid6=0x",
&gi_rec.guid_info.guid[6]);
PARSE_AHEAD(p, net64, " guid7=0x",
&gi_rec.guid_info.guid[7]);
if (load_guidinfo(p_osm, base_guid, &gi_rec))
rereg_clients = 1;
}
/*
* p_next_mgrp points to the multicast group now being parsed.
* p_prev_mgrp points to the last multicast group we parsed.
* We decide whether to keep or delete each multicast group
* only when we finish parsing it's member records. if the
* group has full members, or it is a "well known group" we
* keep it.
*/
if (p_prev_mgrp != p_next_mgrp) {
if (p_prev_mgrp)
sa_db_file_load_handle_mgrp(p_osm, p_prev_mgrp);
p_prev_mgrp = p_next_mgrp;
}
}
if (p_next_mgrp)
sa_db_file_load_handle_mgrp(p_osm, p_prev_mgrp);
/*
* If loading succeeded, do whatever 'no_clients_rereg' says.
* If loading failed at some point, turn off the 'no_clients_rereg'
* option (turn on re-registration requests).
*/
if (rereg_clients)
p_osm->subn.opt.no_clients_rereg = FALSE;
/* We've just finished loading SA DB file - clear the "dirty" flag */
p_osm->sa.dirty = FALSE;
_error:
fclose(file);
return ret;
}