1/*
2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2008 Xsigo Systems Inc.  All rights reserved.
6 *
7 * This software is available to you under a choice of one of two
8 * licenses.  You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
12 *
13 *     Redistribution and use in source and binary forms, with or
14 *     without modification, are permitted provided that the following
15 *     conditions are met:
16 *
17 *      - Redistributions of source code must retain the above
18 *        copyright notice, this list of conditions and the following
19 *        disclaimer.
20 *
21 *      - Redistributions in binary form must reproduce the above
22 *        copyright notice, this list of conditions and the following
23 *        disclaimer in the documentation and/or other materials
24 *        provided with the distribution.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE.
34 *
35 */
36
37/*
38 * Abstract:
39 *    Implementation of osm_sa_t.
40 * This object represents the Subnet Administration object.
41 * This object is part of the opensm family of objects.
42 */
43
44#if HAVE_CONFIG_H
45#  include <config.h>
46#endif				/* HAVE_CONFIG_H */
47
48#include <string.h>
49#include <ctype.h>
50#include <errno.h>
51#include <stdlib.h>
52#include <sys/types.h>
53#include <sys/stat.h>
54#include <complib/cl_qmap.h>
55#include <complib/cl_passivelock.h>
56#include <complib/cl_debug.h>
57#include <iba/ib_types.h>
58#include <opensm/osm_sa.h>
59#include <opensm/osm_madw.h>
60#include <opensm/osm_log.h>
61#include <opensm/osm_subnet.h>
62#include <opensm/osm_mad_pool.h>
63#include <opensm/osm_msgdef.h>
64#include <opensm/osm_opensm.h>
65#include <opensm/osm_multicast.h>
66#include <opensm/osm_inform.h>
67#include <opensm/osm_service.h>
68#include <opensm/osm_helper.h>
69#include <vendor/osm_vendor_api.h>
70
71#define  OSM_SA_INITIAL_TID_VALUE 0xabc
72
73extern void osm_cpi_rcv_process(IN void *context, IN void *data);
74extern void osm_gir_rcv_process(IN void *context, IN void *data);
75extern void osm_infr_rcv_process(IN void *context, IN void *data);
76extern void osm_infir_rcv_process(IN void *context, IN void *data);
77extern void osm_lftr_rcv_process(IN void *context, IN void *data);
78extern void osm_lr_rcv_process(IN void *context, IN void *data);
79extern void osm_mcmr_rcv_process(IN void *context, IN void *data);
80extern void osm_mftr_rcv_process(IN void *context, IN void *data);
81extern void osm_mpr_rcv_process(IN void *context, IN void *data);
82extern void osm_nr_rcv_process(IN void *context, IN void *data);
83extern void osm_pr_rcv_process(IN void *context, IN void *data);
84extern void osm_pkey_rec_rcv_process(IN void *context, IN void *data);
85extern void osm_pir_rcv_process(IN void *context, IN void *data);
86extern void osm_sr_rcv_process(IN void *context, IN void *data);
87extern void osm_slvl_rec_rcv_process(IN void *context, IN void *data);
88extern void osm_smir_rcv_process(IN void *context, IN void *data);
89extern void osm_sir_rcv_process(IN void *context, IN void *data);
90extern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data);
91extern void osm_sr_rcv_lease_cb(IN void *context);
92
93/**********************************************************************
94 **********************************************************************/
95void osm_sa_construct(IN osm_sa_t * const p_sa)
96{
97	memset(p_sa, 0, sizeof(*p_sa));
98	p_sa->state = OSM_SA_STATE_INIT;
99	p_sa->sa_trans_id = OSM_SA_INITIAL_TID_VALUE;
100
101	cl_timer_construct(&p_sa->sr_timer);
102}
103
104/**********************************************************************
105 **********************************************************************/
106void osm_sa_shutdown(IN osm_sa_t * const p_sa)
107{
108	ib_api_status_t status;
109	OSM_LOG_ENTER(p_sa->p_log);
110
111	cl_timer_stop(&p_sa->sr_timer);
112
113	/* unbind from the mad service */
114	status = osm_sa_mad_ctrl_unbind(&p_sa->mad_ctrl);
115
116	/* remove any registered dispatcher message */
117	cl_disp_unregister(p_sa->nr_disp_h);
118	cl_disp_unregister(p_sa->pir_disp_h);
119	cl_disp_unregister(p_sa->gir_disp_h);
120	cl_disp_unregister(p_sa->lr_disp_h);
121	cl_disp_unregister(p_sa->pr_disp_h);
122#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
123	cl_disp_unregister(p_sa->mpr_disp_h);
124#endif
125	cl_disp_unregister(p_sa->smir_disp_h);
126	cl_disp_unregister(p_sa->mcmr_disp_h);
127	cl_disp_unregister(p_sa->sr_disp_h);
128	cl_disp_unregister(p_sa->infr_disp_h);
129	cl_disp_unregister(p_sa->infir_disp_h);
130	cl_disp_unregister(p_sa->vlarb_disp_h);
131	cl_disp_unregister(p_sa->slvl_disp_h);
132	cl_disp_unregister(p_sa->pkey_disp_h);
133	cl_disp_unregister(p_sa->lft_disp_h);
134	cl_disp_unregister(p_sa->sir_disp_h);
135	cl_disp_unregister(p_sa->mft_disp_h);
136	osm_sa_mad_ctrl_destroy(&p_sa->mad_ctrl);
137
138	OSM_LOG_EXIT(p_sa->p_log);
139}
140
141/**********************************************************************
142 **********************************************************************/
143void osm_sa_destroy(IN osm_sa_t * const p_sa)
144{
145	OSM_LOG_ENTER(p_sa->p_log);
146
147	p_sa->state = OSM_SA_STATE_INIT;
148
149	cl_timer_destroy(&p_sa->sr_timer);
150
151	OSM_LOG_EXIT(p_sa->p_log);
152}
153
154/**********************************************************************
155 **********************************************************************/
156ib_api_status_t
157osm_sa_init(IN osm_sm_t * const p_sm,
158	    IN osm_sa_t * const p_sa,
159	    IN osm_subn_t * const p_subn,
160	    IN osm_vendor_t * const p_vendor,
161	    IN osm_mad_pool_t * const p_mad_pool,
162	    IN osm_log_t * const p_log,
163	    IN osm_stats_t * const p_stats,
164	    IN cl_dispatcher_t * const p_disp, IN cl_plock_t * const p_lock)
165{
166	ib_api_status_t status = IB_SUCCESS;
167
168	OSM_LOG_ENTER(p_log);
169
170	p_sa->sm = p_sm;
171	p_sa->p_subn = p_subn;
172	p_sa->p_vendor = p_vendor;
173	p_sa->p_mad_pool = p_mad_pool;
174	p_sa->p_log = p_log;
175	p_sa->p_disp = p_disp;
176	p_sa->p_lock = p_lock;
177
178	p_sa->state = OSM_SA_STATE_READY;
179
180	status = osm_sa_mad_ctrl_init(&p_sa->mad_ctrl,
181				      p_sa,
182				      p_sa->p_mad_pool,
183				      p_sa->p_vendor,
184				      p_subn, p_log, p_stats, p_disp);
185	if (status != IB_SUCCESS)
186		goto Exit;
187
188	status = cl_timer_init(&p_sa->sr_timer, osm_sr_rcv_lease_cb, p_sa);
189	if (status != IB_SUCCESS)
190		goto Exit;
191
192	p_sa->cpi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_CLASS_PORT_INFO,
193					    osm_cpi_rcv_process, p_sa);
194	if (p_sa->cpi_disp_h == CL_DISP_INVALID_HANDLE)
195		goto Exit;
196
197	p_sa->nr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_RECORD,
198					   osm_nr_rcv_process, p_sa);
199	if (p_sa->nr_disp_h == CL_DISP_INVALID_HANDLE)
200		goto Exit;
201
202	p_sa->pir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORTINFO_RECORD,
203					    osm_pir_rcv_process, p_sa);
204	if (p_sa->pir_disp_h == CL_DISP_INVALID_HANDLE)
205		goto Exit;
206
207	p_sa->gir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_GUIDINFO_RECORD,
208					    osm_gir_rcv_process, p_sa);
209	if (p_sa->gir_disp_h == CL_DISP_INVALID_HANDLE)
210		goto Exit;
211
212	p_sa->lr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LINK_RECORD,
213					   osm_lr_rcv_process, p_sa);
214	if (p_sa->lr_disp_h == CL_DISP_INVALID_HANDLE)
215		goto Exit;
216
217	p_sa->pr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PATH_RECORD,
218					   osm_pr_rcv_process, p_sa);
219	if (p_sa->pr_disp_h == CL_DISP_INVALID_HANDLE)
220		goto Exit;
221
222#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
223	p_sa->mpr_disp_h =
224	    cl_disp_register(p_disp, OSM_MSG_MAD_MULTIPATH_RECORD,
225			     osm_mpr_rcv_process, p_sa);
226	if (p_sa->mpr_disp_h == CL_DISP_INVALID_HANDLE)
227		goto Exit;
228#endif
229
230	p_sa->smir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SMINFO_RECORD,
231					     osm_smir_rcv_process, p_sa);
232	if (p_sa->smir_disp_h == CL_DISP_INVALID_HANDLE)
233		goto Exit;
234
235	p_sa->mcmr_disp_h =
236	    cl_disp_register(p_disp, OSM_MSG_MAD_MCMEMBER_RECORD,
237			     osm_mcmr_rcv_process, p_sa);
238	if (p_sa->mcmr_disp_h == CL_DISP_INVALID_HANDLE)
239		goto Exit;
240
241	p_sa->sr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SERVICE_RECORD,
242					   osm_sr_rcv_process, p_sa);
243	if (p_sa->sr_disp_h == CL_DISP_INVALID_HANDLE)
244		goto Exit;
245
246	p_sa->infr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO,
247					     osm_infr_rcv_process, p_sa);
248	if (p_sa->infr_disp_h == CL_DISP_INVALID_HANDLE)
249		goto Exit;
250
251	p_sa->infir_disp_h =
252	    cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO_RECORD,
253			     osm_infir_rcv_process, p_sa);
254	if (p_sa->infir_disp_h == CL_DISP_INVALID_HANDLE)
255		goto Exit;
256
257	p_sa->vlarb_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB_RECORD,
258					      osm_vlarb_rec_rcv_process, p_sa);
259	if (p_sa->vlarb_disp_h == CL_DISP_INVALID_HANDLE)
260		goto Exit;
261
262	p_sa->slvl_disp_h =
263	    cl_disp_register(p_disp, OSM_MSG_MAD_SLVL_TBL_RECORD,
264			     osm_slvl_rec_rcv_process, p_sa);
265	if (p_sa->slvl_disp_h == CL_DISP_INVALID_HANDLE)
266		goto Exit;
267
268	p_sa->pkey_disp_h =
269	    cl_disp_register(p_disp, OSM_MSG_MAD_PKEY_TBL_RECORD,
270			     osm_pkey_rec_rcv_process, p_sa);
271	if (p_sa->pkey_disp_h == CL_DISP_INVALID_HANDLE)
272		goto Exit;
273
274	p_sa->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT_RECORD,
275					    osm_lftr_rcv_process, p_sa);
276	if (p_sa->lft_disp_h == CL_DISP_INVALID_HANDLE)
277		goto Exit;
278
279	p_sa->sir_disp_h =
280	    cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO_RECORD,
281			     osm_sir_rcv_process, p_sa);
282	if (p_sa->sir_disp_h == CL_DISP_INVALID_HANDLE)
283		goto Exit;
284
285	p_sa->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT_RECORD,
286					    osm_mftr_rcv_process, p_sa);
287	if (p_sa->mft_disp_h == CL_DISP_INVALID_HANDLE)
288		goto Exit;
289
290Exit:
291	OSM_LOG_EXIT(p_log);
292	return (status);
293}
294
295/**********************************************************************
296 **********************************************************************/
297ib_api_status_t
298osm_sa_bind(IN osm_sa_t * const p_sa, IN const ib_net64_t port_guid)
299{
300	ib_api_status_t status;
301
302	OSM_LOG_ENTER(p_sa->p_log);
303
304	status = osm_sa_mad_ctrl_bind(&p_sa->mad_ctrl, port_guid);
305
306	if (status != IB_SUCCESS) {
307		OSM_LOG(p_sa->p_log, OSM_LOG_ERROR, "ERR 4C03: "
308			"SA MAD Controller bind failed (%s)\n",
309			ib_get_err_str(status));
310		goto Exit;
311	}
312
313Exit:
314	OSM_LOG_EXIT(p_sa->p_log);
315	return (status);
316}
317
318ib_api_status_t osm_sa_send(osm_sa_t *sa,
319			    IN osm_madw_t * const p_madw,
320			    IN boolean_t const resp_expected)
321{
322	ib_api_status_t status;
323
324	cl_atomic_inc(&sa->p_subn->p_osm->stats.sa_mads_sent);
325	status = osm_vendor_send(p_madw->h_bind, p_madw, resp_expected);
326	if (status != IB_SUCCESS) {
327		cl_atomic_dec(&sa->p_subn->p_osm->stats.sa_mads_sent);
328		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C04: "
329			"osm_vendor_send failed, status = %s\n",
330			ib_get_err_str(status));
331	}
332	return status;
333}
334
335void
336osm_sa_send_error(IN osm_sa_t * sa,
337		  IN const osm_madw_t * const p_madw,
338		  IN const ib_net16_t sa_status)
339{
340	osm_madw_t *p_resp_madw;
341	ib_sa_mad_t *p_resp_sa_mad;
342	ib_sa_mad_t *p_sa_mad;
343
344	OSM_LOG_ENTER(sa->p_log);
345
346	/* avoid races - if we are exiting - exit */
347	if (osm_exit_flag) {
348		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
349			"Ignoring requested send after exit\n");
350		goto Exit;
351	}
352
353	p_resp_madw = osm_mad_pool_get(sa->p_mad_pool,
354				       p_madw->h_bind, MAD_BLOCK_SIZE,
355				       &p_madw->mad_addr);
356
357	if (p_resp_madw == NULL) {
358		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C07: "
359			"Unable to acquire response MAD\n");
360		goto Exit;
361	}
362
363	p_resp_sa_mad = osm_madw_get_sa_mad_ptr(p_resp_madw);
364	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
365
366	/*  Copy the MAD header back into the response mad */
367	*p_resp_sa_mad = *p_sa_mad;
368	p_resp_sa_mad->status = sa_status;
369
370	if (p_resp_sa_mad->method == IB_MAD_METHOD_SET)
371		p_resp_sa_mad->method = IB_MAD_METHOD_GET;
372	else if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE)
373		p_resp_sa_mad->attr_offset = 0;
374
375	p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
376
377	/*
378	 * C15-0.1.5 - always return SM_Key = 0 (table 185 p 884)
379	 */
380	p_resp_sa_mad->sm_key = 0;
381
382	/*
383	 * o15-0.2.7 - The PathRecord Attribute ID shall be used in
384	 * the response (to a SubnAdmGetMulti(MultiPathRecord)
385	 */
386	if (p_resp_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD)
387		p_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
388
389	if (osm_log_is_active(sa->p_log, OSM_LOG_FRAMES))
390		osm_dump_sa_mad(sa->p_log, p_resp_sa_mad, OSM_LOG_FRAMES);
391
392	osm_sa_send(sa, p_resp_madw, FALSE);
393
394Exit:
395	OSM_LOG_EXIT(sa->p_log);
396}
397
398void osm_sa_respond(osm_sa_t *sa, osm_madw_t *madw, size_t attr_size,
399		    cl_qlist_t *list)
400{
401	struct item_data {
402		cl_list_item_t list;
403		char data[0];
404	};
405	cl_list_item_t *item;
406	osm_madw_t *resp_madw;
407	ib_sa_mad_t *sa_mad, *resp_sa_mad;
408	unsigned num_rec, i;
409#ifndef VENDOR_RMPP_SUPPORT
410	unsigned trim_num_rec;
411#endif
412	void *p;
413
414	sa_mad = osm_madw_get_sa_mad_ptr(madw);
415	num_rec = cl_qlist_count(list);
416
417	/*
418	 * C15-0.1.30:
419	 * If we do a SubnAdmGet and got more than one record it is an error!
420	 */
421	if (sa_mad->method == IB_MAD_METHOD_GET && num_rec > 1) {
422		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C05: "
423			"Got more than one record for SubnAdmGet (%u)\n",
424			num_rec);
425		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_TOO_MANY_RECORDS);
426		goto Exit;
427	}
428
429#ifndef VENDOR_RMPP_SUPPORT
430	trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / attr_size;
431	if (trim_num_rec < num_rec) {
432		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
433			"Number of records:%u trimmed to:%u to fit in one MAD\n",
434			num_rec, trim_num_rec);
435		num_rec = trim_num_rec;
436	}
437#endif
438
439	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Returning %u records\n", num_rec);
440
441	if (sa_mad->method == IB_MAD_METHOD_GET && num_rec == 0) {
442		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RECORDS);
443		goto Exit;
444	}
445
446	/*
447	 * Get a MAD to reply. Address of Mad is in the received mad_wrapper
448	 */
449	resp_madw = osm_mad_pool_get(sa->p_mad_pool, madw->h_bind,
450				     num_rec * attr_size + IB_SA_MAD_HDR_SIZE,
451				     &madw->mad_addr);
452	if (!resp_madw) {
453		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C06: "
454			"osm_mad_pool_get failed\n");
455		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RESOURCES);
456		goto Exit;
457	}
458
459	resp_sa_mad = osm_madw_get_sa_mad_ptr(resp_madw);
460
461	/*
462	   Copy the MAD header back into the response mad.
463	   Set the 'R' bit and the payload length,
464	   Then copy all records from the list into the response payload.
465	 */
466
467	memcpy(resp_sa_mad, sa_mad, IB_SA_MAD_HDR_SIZE);
468	if (resp_sa_mad->method == IB_MAD_METHOD_SET)
469		resp_sa_mad->method = IB_MAD_METHOD_GET;
470	resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
471	/* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
472	resp_sa_mad->sm_key = 0;
473
474	/* Fill in the offset (paylen will be done by the rmpp SAR) */
475	resp_sa_mad->attr_offset = num_rec ? ib_get_attr_offset(attr_size) : 0;
476
477	p = ib_sa_mad_get_payload_ptr(resp_sa_mad);
478
479#ifndef VENDOR_RMPP_SUPPORT
480	/* we support only one packet RMPP - so we will set the first and
481	   last flags for gettable */
482	if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) {
483		resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;
484		resp_sa_mad->rmpp_flags =
485		    IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST |
486		    IB_RMPP_FLAG_ACTIVE;
487	}
488#else
489	/* forcefully define the packet as RMPP one */
490	if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
491		resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
492#endif
493
494	for (i = 0; i < num_rec; i++) {
495		item = cl_qlist_remove_head(list);
496		memcpy(p, ((struct item_data *)item)->data, attr_size);
497		p += attr_size;
498		free(item);
499	}
500
501	osm_sa_send(sa, resp_madw, FALSE);
502
503	osm_dump_sa_mad(sa->p_log, resp_sa_mad, OSM_LOG_FRAMES);
504Exit:
505	/* need to set the mem free ... */
506	item = cl_qlist_remove_head(list);
507	while (item != cl_qlist_end(list)) {
508		free(item);
509		item = cl_qlist_remove_head(list);
510	}
511}
512
513/**********************************************************************
514 **********************************************************************/
515/*
516 *  SA DB Dumper
517 *
518 */
519
520struct opensm_dump_context {
521	osm_opensm_t *p_osm;
522	FILE *file;
523};
524
525static int
526opensm_dump_to_file(osm_opensm_t * p_osm, const char *file_name,
527		    void (*dump_func) (osm_opensm_t * p_osm, FILE * file))
528{
529	char path[1024];
530	FILE *file;
531
532	snprintf(path, sizeof(path), "%s/%s",
533		 p_osm->subn.opt.dump_files_dir, file_name);
534
535	file = fopen(path, "w");
536	if (!file) {
537		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C01: "
538			"cannot open file \'%s\': %s\n",
539			file_name, strerror(errno));
540		return -1;
541	}
542
543	chmod(path, S_IRUSR | S_IWUSR);
544
545	dump_func(p_osm, file);
546
547	fclose(file);
548	return 0;
549}
550
551static void mcast_mgr_dump_one_port(cl_map_item_t * p_map_item, void *cxt)
552{
553	FILE *file = ((struct opensm_dump_context *)cxt)->file;
554	osm_mcm_port_t *p_mcm_port = (osm_mcm_port_t *) p_map_item;
555
556	fprintf(file, "mcm_port: "
557		"port_gid=0x%016" PRIx64 ":0x%016" PRIx64 " "
558		"scope_state=0x%02x proxy_join=0x%x" "\n\n",
559		cl_ntoh64(p_mcm_port->port_gid.unicast.prefix),
560		cl_ntoh64(p_mcm_port->port_gid.unicast.interface_id),
561		p_mcm_port->scope_state, p_mcm_port->proxy_join);
562}
563
564static void sa_dump_one_mgrp(osm_mgrp_t *p_mgrp, void *cxt)
565{
566	struct opensm_dump_context dump_context;
567	osm_opensm_t *p_osm = ((struct opensm_dump_context *)cxt)->p_osm;
568	FILE *file = ((struct opensm_dump_context *)cxt)->file;
569
570	fprintf(file, "MC Group 0x%04x %s:"
571		" mgid=0x%016" PRIx64 ":0x%016" PRIx64
572		" port_gid=0x%016" PRIx64 ":0x%016" PRIx64
573		" qkey=0x%08x mlid=0x%04x mtu=0x%02x tclass=0x%02x"
574		" pkey=0x%04x rate=0x%02x pkt_life=0x%02x sl_flow_hop=0x%08x"
575		" scope_state=0x%02x proxy_join=0x%x" "\n\n",
576		cl_ntoh16(p_mgrp->mlid),
577		p_mgrp->well_known ? " (well known)" : "",
578		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix),
579		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id),
580		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.prefix),
581		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.interface_id),
582		cl_ntoh32(p_mgrp->mcmember_rec.qkey),
583		cl_ntoh16(p_mgrp->mcmember_rec.mlid),
584		p_mgrp->mcmember_rec.mtu,
585		p_mgrp->mcmember_rec.tclass,
586		cl_ntoh16(p_mgrp->mcmember_rec.pkey),
587		p_mgrp->mcmember_rec.rate,
588		p_mgrp->mcmember_rec.pkt_life,
589		cl_ntoh32(p_mgrp->mcmember_rec.sl_flow_hop),
590		p_mgrp->mcmember_rec.scope_state,
591		p_mgrp->mcmember_rec.proxy_join);
592
593	dump_context.p_osm = p_osm;
594	dump_context.file = file;
595
596	cl_qmap_apply_func(&p_mgrp->mcm_port_tbl,
597			   mcast_mgr_dump_one_port, &dump_context);
598}
599
600static void sa_dump_one_inform(cl_list_item_t * p_list_item, void *cxt)
601{
602	FILE *file = ((struct opensm_dump_context *)cxt)->file;
603	osm_infr_t *p_infr = (osm_infr_t *) p_list_item;
604	ib_inform_info_record_t *p_iir = &p_infr->inform_record;
605
606	fprintf(file, "InformInfo Record:"
607		" subscriber_gid=0x%016" PRIx64 ":0x%016" PRIx64
608		" subscriber_enum=0x%x"
609		" InformInfo:"
610		" gid=0x%016" PRIx64 ":0x%016" PRIx64
611		" lid_range_begin=0x%x"
612		" lid_range_end=0x%x"
613		" is_generic=0x%x"
614		" subscribe=0x%x"
615		" trap_type=0x%x"
616		" trap_num=0x%x"
617		" qpn_resp_time_val=0x%x"
618		" node_type=0x%06x"
619		" rep_addr: lid=0x%04x path_bits=0x%02x static_rate=0x%02x"
620		" remote_qp=0x%08x remote_qkey=0x%08x pkey_ix=0x%04x sl=0x%02x"
621		"\n\n",
622		cl_ntoh64(p_iir->subscriber_gid.unicast.prefix),
623		cl_ntoh64(p_iir->subscriber_gid.unicast.interface_id),
624		cl_ntoh16(p_iir->subscriber_enum),
625		cl_ntoh64(p_iir->inform_info.gid.unicast.prefix),
626		cl_ntoh64(p_iir->inform_info.gid.unicast.interface_id),
627		cl_ntoh16(p_iir->inform_info.lid_range_begin),
628		cl_ntoh16(p_iir->inform_info.lid_range_end),
629		p_iir->inform_info.is_generic,
630		p_iir->inform_info.subscribe,
631		cl_ntoh16(p_iir->inform_info.trap_type),
632		cl_ntoh16(p_iir->inform_info.g_or_v.generic.trap_num),
633		cl_ntoh32(p_iir->inform_info.g_or_v.generic.qpn_resp_time_val),
634		cl_ntoh32(ib_inform_info_get_prod_type(&p_iir->inform_info)),
635		cl_ntoh16(p_infr->report_addr.dest_lid),
636		p_infr->report_addr.path_bits,
637		p_infr->report_addr.static_rate,
638		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qp),
639		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qkey),
640		p_infr->report_addr.addr_type.gsi.pkey_ix,
641		p_infr->report_addr.addr_type.gsi.service_level);
642}
643
644static void sa_dump_one_service(cl_list_item_t * p_list_item, void *cxt)
645{
646	FILE *file = ((struct opensm_dump_context *)cxt)->file;
647	osm_svcr_t *p_svcr = (osm_svcr_t *) p_list_item;
648	ib_service_record_t *p_sr = &p_svcr->service_record;
649
650	fprintf(file, "Service Record: id=0x%016" PRIx64
651		" gid=0x%016" PRIx64 ":0x%016" PRIx64
652		" pkey=0x%x"
653		" lease=0x%x"
654		" key=0x%02x%02x%02x%02x%02x%02x%02x%02x"
655		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
656		" name=\'%s\'"
657		" data8=0x%02x%02x%02x%02x%02x%02x%02x%02x"
658		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
659		" data16=0x%04x%04x%04x%04x:0x%04x%04x%04x%04x"
660		" data32=0x%08x%08x:0x%08x%08x"
661		" data64=0x%016" PRIx64 ":0x%016" PRIx64
662		" modified_time=0x%x lease_period=0x%x\n\n",
663		cl_ntoh64(p_sr->service_id),
664		cl_ntoh64(p_sr->service_gid.unicast.prefix),
665		cl_ntoh64(p_sr->service_gid.unicast.interface_id),
666		cl_ntoh16(p_sr->service_pkey),
667		cl_ntoh32(p_sr->service_lease),
668		p_sr->service_key[0], p_sr->service_key[1],
669		p_sr->service_key[2], p_sr->service_key[3],
670		p_sr->service_key[4], p_sr->service_key[5],
671		p_sr->service_key[6], p_sr->service_key[7],
672		p_sr->service_key[8], p_sr->service_key[9],
673		p_sr->service_key[10], p_sr->service_key[11],
674		p_sr->service_key[12], p_sr->service_key[13],
675		p_sr->service_key[14], p_sr->service_key[15],
676		p_sr->service_name,
677		p_sr->service_data8[0], p_sr->service_data8[1],
678		p_sr->service_data8[2], p_sr->service_data8[3],
679		p_sr->service_data8[4], p_sr->service_data8[5],
680		p_sr->service_data8[6], p_sr->service_data8[7],
681		p_sr->service_data8[8], p_sr->service_data8[9],
682		p_sr->service_data8[10], p_sr->service_data8[11],
683		p_sr->service_data8[12], p_sr->service_data8[13],
684		p_sr->service_data8[14], p_sr->service_data8[15],
685		cl_ntoh16(p_sr->service_data16[0]),
686		cl_ntoh16(p_sr->service_data16[1]),
687		cl_ntoh16(p_sr->service_data16[2]),
688		cl_ntoh16(p_sr->service_data16[3]),
689		cl_ntoh16(p_sr->service_data16[4]),
690		cl_ntoh16(p_sr->service_data16[5]),
691		cl_ntoh16(p_sr->service_data16[6]),
692		cl_ntoh16(p_sr->service_data16[7]),
693		cl_ntoh32(p_sr->service_data32[0]),
694		cl_ntoh32(p_sr->service_data32[1]),
695		cl_ntoh32(p_sr->service_data32[2]),
696		cl_ntoh32(p_sr->service_data32[3]),
697		cl_ntoh64(p_sr->service_data64[0]),
698		cl_ntoh64(p_sr->service_data64[1]),
699		p_svcr->modified_time, p_svcr->lease_period);
700}
701
702static void sa_dump_all_sa(osm_opensm_t * p_osm, FILE * file)
703{
704	struct opensm_dump_context dump_context;
705	osm_mgrp_t *p_mgrp;
706	int i;
707
708	dump_context.p_osm = p_osm;
709	dump_context.file = file;
710	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump multicast:\n");
711	cl_plock_acquire(&p_osm->lock);
712	for (i = 0; i <= p_osm->subn.max_mcast_lid_ho - IB_LID_MCAST_START_HO;
713	     i++) {
714		p_mgrp = p_osm->subn.mgroups[i];
715		if (p_mgrp)
716			sa_dump_one_mgrp(p_mgrp, &dump_context);
717	}
718	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump inform:\n");
719	cl_qlist_apply_func(&p_osm->subn.sa_infr_list,
720			    sa_dump_one_inform, &dump_context);
721	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump services:\n");
722	cl_qlist_apply_func(&p_osm->subn.sa_sr_list,
723			    sa_dump_one_service, &dump_context);
724	cl_plock_release(&p_osm->lock);
725}
726
727int osm_sa_db_file_dump(osm_opensm_t * p_osm)
728{
729	return opensm_dump_to_file(p_osm, "opensm-sa.dump", sa_dump_all_sa);
730}
731
732/*
733 *  SA DB Loader
734 */
735static osm_mgrp_t *load_mcgroup(osm_opensm_t * p_osm, ib_net16_t mlid,
736				ib_member_rec_t * p_mcm_rec,
737				unsigned well_known)
738{
739	ib_net64_t comp_mask;
740	osm_mgrp_t *p_mgrp;
741
742	cl_plock_excl_acquire(&p_osm->lock);
743
744	p_mgrp = osm_get_mgrp_by_mlid(&p_osm->subn, mlid);
745	if (p_mgrp) {
746		if (!memcmp(&p_mgrp->mcmember_rec.mgid, &p_mcm_rec->mgid,
747			    sizeof(ib_gid_t))) {
748			OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
749				"mgrp %04x is already here.", cl_ntoh16(mlid));
750			goto _out;
751		}
752		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
753			"mlid %04x is already used by another MC group. Will "
754			"request clients reregistration.\n", cl_ntoh16(mlid));
755		p_mgrp = NULL;
756		goto _out;
757	}
758
759	comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL
760	    | IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL;
761	if (osm_mcmr_rcv_find_or_create_new_mgrp(&p_osm->sa,
762						 comp_mask, p_mcm_rec,
763						 &p_mgrp) != IB_SUCCESS ||
764	    !p_mgrp || p_mgrp->mlid != mlid) {
765		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
766			"cannot create MC group with mlid 0x%04x and mgid "
767			"0x%016" PRIx64 ":0x%016" PRIx64 "\n", cl_ntoh16(mlid),
768			cl_ntoh64(p_mcm_rec->mgid.unicast.prefix),
769			cl_ntoh64(p_mcm_rec->mgid.unicast.interface_id));
770		p_mgrp = NULL;
771	} else if (well_known)
772		p_mgrp->well_known = TRUE;
773
774_out:
775	cl_plock_release(&p_osm->lock);
776
777	return p_mgrp;
778}
779
780static int load_svcr(osm_opensm_t * p_osm, ib_service_record_t * sr,
781		     uint32_t modified_time, uint32_t lease_period)
782{
783	osm_svcr_t *p_svcr;
784	int ret = 0;
785
786	cl_plock_excl_acquire(&p_osm->lock);
787
788	if (osm_svcr_get_by_rid(&p_osm->subn, &p_osm->log, sr)) {
789		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
790			"ServiceRecord already exists\n");
791		goto _out;
792	}
793
794	if (!(p_svcr = osm_svcr_new(sr))) {
795		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
796			"cannot allocate new service struct\n");
797		ret = -1;
798		goto _out;
799	}
800
801	p_svcr->modified_time = modified_time;
802	p_svcr->lease_period = lease_period;
803
804	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding ServiceRecord...\n");
805
806	osm_svcr_insert_to_db(&p_osm->subn, &p_osm->log, p_svcr);
807
808	if (lease_period != 0xffffffff)
809		cl_timer_trim(&p_osm->sa.sr_timer, 1000);
810
811_out:
812	cl_plock_release(&p_osm->lock);
813
814	return ret;
815}
816
817static int load_infr(osm_opensm_t * p_osm, ib_inform_info_record_t * iir,
818		     osm_mad_addr_t * addr)
819{
820	osm_infr_t infr, *p_infr;
821	int ret = 0;
822
823	infr.h_bind = p_osm->sa.mad_ctrl.h_bind;
824	infr.sa = &p_osm->sa;
825	/* other possible way to restore mad_addr partially is
826	   to extract qpn from InformInfo and to find lid by gid */
827	infr.report_addr = *addr;
828	infr.inform_record = *iir;
829
830	cl_plock_excl_acquire(&p_osm->lock);
831	if (osm_infr_get_by_rec(&p_osm->subn, &p_osm->log, &infr)) {
832		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
833			"InformInfo Record already exists\n");
834		goto _out;
835	}
836
837	if (!(p_infr = osm_infr_new(&infr))) {
838		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
839			"cannot allocate new infr struct\n");
840		ret = -1;
841		goto _out;
842	}
843
844	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding InformInfo Record...\n");
845
846	osm_infr_insert_to_db(&p_osm->subn, &p_osm->log, p_infr);
847
848_out:
849	cl_plock_release(&p_osm->lock);
850
851	return ret;
852}
853
854#define UNPACK_FUNC(name,x) \
855static int unpack_##name##x(char *p, uint##x##_t *val_ptr) \
856{ \
857	char *q; \
858	unsigned long long num; \
859	num = strtoull(p, &q, 16); \
860	if (num > ~((uint##x##_t)0x0) \
861	    || q == p || (!isspace(*q) && *q != ':')) { \
862		*val_ptr = 0; \
863		return -1; \
864	} \
865	*val_ptr = cl_hton##x((uint##x##_t)num); \
866	return (int)(q - p); \
867}
868
869#define cl_hton8(x) (x)
870
871UNPACK_FUNC(net, 8);
872UNPACK_FUNC(net, 16);
873UNPACK_FUNC(net, 32);
874UNPACK_FUNC(net, 64);
875
876static int unpack_string(char *p, uint8_t * buf, unsigned len)
877{
878	char *q = p;
879	char delim = ' ';
880
881	if (*q == '\'' || *q == '\"')
882		delim = *q++;
883	while (--len && *q && *q != delim)
884		*buf++ = *q++;
885	*buf = '\0';
886	if (*q == delim && delim != ' ')
887		q++;
888	return (int)(q - p);
889}
890
891static int unpack_string64(char *p, uint8_t * buf)
892{
893	return unpack_string(p, buf, 64);
894}
895
896#define PARSE_AHEAD(p, x, name, val_ptr) { int _ret; \
897	p = strstr(p, name); \
898	if (!p) { \
899		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \
900			"PARSE ERROR: %s:%u: cannot find \"%s\" string\n", \
901			file_name, lineno, (name)); \
902		ret = -2; \
903		goto _error; \
904	} \
905	p += strlen(name); \
906	_ret = unpack_##x(p, (val_ptr)); \
907	if (_ret < 0) { \
908		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \
909			"PARSE ERROR: %s:%u: cannot parse "#x" value " \
910			"after \"%s\"\n", file_name, lineno, (name)); \
911		ret = _ret; \
912		goto _error; \
913	} \
914	p += _ret; \
915}
916
917int osm_sa_db_file_load(osm_opensm_t * p_osm)
918{
919	char line[1024];
920	char *file_name;
921	FILE *file;
922	int ret = 0;
923	osm_mgrp_t *p_mgrp = NULL;
924	unsigned rereg_clients = 0;
925	unsigned lineno;
926
927	file_name = p_osm->subn.opt.sa_db_file;
928	if (!file_name) {
929		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
930			"sa db file name is not specifed. Skip restore\n");
931		return 0;
932	}
933
934	file = fopen(file_name, "r");
935	if (!file) {
936		OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 4C02: "
937			"cannot open sa db file \'%s\'. Skip restoring\n",
938			file_name);
939		return -1;
940	}
941
942	lineno = 0;
943
944	while (fgets(line, sizeof(line) - 1, file) != NULL) {
945		char *p;
946		uint8_t val;
947
948		lineno++;
949
950		p = line;
951		while (isspace(*p))
952			p++;
953
954		if (*p == '#')
955			continue;
956
957		if (!strncmp(p, "MC Group", 8)) {
958			ib_member_rec_t mcm_rec;
959			ib_net16_t mlid;
960			unsigned well_known = 0;
961
962			p_mgrp = NULL;
963			memset(&mcm_rec, 0, sizeof(mcm_rec));
964
965			PARSE_AHEAD(p, net16, " 0x", &mlid);
966			if (strstr(p, "well known"))
967				well_known = 1;
968			PARSE_AHEAD(p, net64, " mgid=0x",
969				    &mcm_rec.mgid.unicast.prefix);
970			PARSE_AHEAD(p, net64, ":0x",
971				    &mcm_rec.mgid.unicast.interface_id);
972			PARSE_AHEAD(p, net64, " port_gid=0x",
973				    &mcm_rec.port_gid.unicast.prefix);
974			PARSE_AHEAD(p, net64, ":0x",
975				    &mcm_rec.port_gid.unicast.interface_id);
976			PARSE_AHEAD(p, net32, " qkey=0x", &mcm_rec.qkey);
977			PARSE_AHEAD(p, net16, " mlid=0x", &mcm_rec.mlid);
978			PARSE_AHEAD(p, net8, " mtu=0x", &mcm_rec.mtu);
979			PARSE_AHEAD(p, net8, " tclass=0x", &mcm_rec.tclass);
980			PARSE_AHEAD(p, net16, " pkey=0x", &mcm_rec.pkey);
981			PARSE_AHEAD(p, net8, " rate=0x", &mcm_rec.rate);
982			PARSE_AHEAD(p, net8, " pkt_life=0x", &mcm_rec.pkt_life);
983			PARSE_AHEAD(p, net32, " sl_flow_hop=0x",
984				    &mcm_rec.sl_flow_hop);
985			PARSE_AHEAD(p, net8, " scope_state=0x",
986				    &mcm_rec.scope_state);
987			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
988			mcm_rec.proxy_join = val;
989
990			p_mgrp = load_mcgroup(p_osm, mlid, &mcm_rec,
991					      well_known);
992			if (!p_mgrp)
993				rereg_clients = 1;
994		} else if (p_mgrp && !strncmp(p, "mcm_port", 8)) {
995			ib_gid_t port_gid;
996			ib_net64_t guid;
997			uint8_t scope_state;
998			boolean_t proxy_join;
999
1000			PARSE_AHEAD(p, net64, " port_gid=0x",
1001				    &port_gid.unicast.prefix);
1002			PARSE_AHEAD(p, net64, ":0x",
1003				    &port_gid.unicast.interface_id);
1004			PARSE_AHEAD(p, net8, " scope_state=0x", &scope_state);
1005			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
1006			proxy_join = val;
1007
1008			guid = port_gid.unicast.interface_id;
1009			if (cl_qmap_get(&p_mgrp->mcm_port_tbl,
1010					port_gid.unicast.interface_id) ==
1011			    cl_qmap_end(&p_mgrp->mcm_port_tbl))
1012				osm_mgrp_add_port(&p_osm->subn, &p_osm->log,
1013						  p_mgrp, &port_gid,
1014						  scope_state, proxy_join);
1015		} else if (!strncmp(p, "Service Record:", 15)) {
1016			ib_service_record_t s_rec;
1017			uint32_t modified_time, lease_period;
1018
1019			p_mgrp = NULL;
1020			memset(&s_rec, 0, sizeof(s_rec));
1021
1022			PARSE_AHEAD(p, net64, " id=0x", &s_rec.service_id);
1023			PARSE_AHEAD(p, net64, " gid=0x",
1024				    &s_rec.service_gid.unicast.prefix);
1025			PARSE_AHEAD(p, net64, ":0x",
1026				    &s_rec.service_gid.unicast.interface_id);
1027			PARSE_AHEAD(p, net16, " pkey=0x", &s_rec.service_pkey);
1028			PARSE_AHEAD(p, net32, " lease=0x",
1029				    &s_rec.service_lease);
1030			PARSE_AHEAD(p, net64, " key=0x",
1031				    (ib_net64_t *) (&s_rec.service_key[0]));
1032			PARSE_AHEAD(p, net64, ":0x",
1033				    (ib_net64_t *) (&s_rec.service_key[8]));
1034			PARSE_AHEAD(p, string64, " name=", s_rec.service_name);
1035			PARSE_AHEAD(p, net64, " data8=0x",
1036				    (ib_net64_t *) (&s_rec.service_data8[0]));
1037			PARSE_AHEAD(p, net64, ":0x",
1038				    (ib_net64_t *) (&s_rec.service_data8[8]));
1039			PARSE_AHEAD(p, net64, " data16=0x",
1040				    (ib_net64_t *) (&s_rec.service_data16[0]));
1041			PARSE_AHEAD(p, net64, ":0x",
1042				    (ib_net64_t *) (&s_rec.service_data16[4]));
1043			PARSE_AHEAD(p, net64, " data32=0x",
1044				    (ib_net64_t *) (&s_rec.service_data32[0]));
1045			PARSE_AHEAD(p, net64, ":0x",
1046				    (ib_net64_t *) (&s_rec.service_data32[2]));
1047			PARSE_AHEAD(p, net64, " data64=0x",
1048				    &s_rec.service_data64[0]);
1049			PARSE_AHEAD(p, net64, ":0x", &s_rec.service_data64[1]);
1050			PARSE_AHEAD(p, net32, " modified_time=0x",
1051				    &modified_time);
1052			PARSE_AHEAD(p, net32, " lease_period=0x",
1053				    &lease_period);
1054
1055			if (load_svcr(p_osm, &s_rec, cl_ntoh32(modified_time),
1056				      cl_ntoh32(lease_period)))
1057				rereg_clients = 1;
1058		} else if (!strncmp(p, "InformInfo Record:", 18)) {
1059			ib_inform_info_record_t i_rec;
1060			osm_mad_addr_t rep_addr;
1061			ib_net16_t val16;
1062
1063			p_mgrp = NULL;
1064			memset(&i_rec, 0, sizeof(i_rec));
1065			memset(&rep_addr, 0, sizeof(rep_addr));
1066
1067			PARSE_AHEAD(p, net64, " subscriber_gid=0x",
1068				    &i_rec.subscriber_gid.unicast.prefix);
1069			PARSE_AHEAD(p, net64, ":0x",
1070				    &i_rec.subscriber_gid.unicast.interface_id);
1071			PARSE_AHEAD(p, net16, " subscriber_enum=0x",
1072				    &i_rec.subscriber_enum);
1073			PARSE_AHEAD(p, net64, " gid=0x",
1074				    &i_rec.inform_info.gid.unicast.prefix);
1075			PARSE_AHEAD(p, net64, ":0x",
1076				    &i_rec.inform_info.gid.unicast.
1077				    interface_id);
1078			PARSE_AHEAD(p, net16, " lid_range_begin=0x",
1079				    &i_rec.inform_info.lid_range_begin);
1080			PARSE_AHEAD(p, net16, " lid_range_end=0x",
1081				    &i_rec.inform_info.lid_range_end);
1082			PARSE_AHEAD(p, net8, " is_generic=0x",
1083				    &i_rec.inform_info.is_generic);
1084			PARSE_AHEAD(p, net8, " subscribe=0x",
1085				    &i_rec.inform_info.subscribe);
1086			PARSE_AHEAD(p, net16, " trap_type=0x",
1087				    &i_rec.inform_info.trap_type);
1088			PARSE_AHEAD(p, net16, " trap_num=0x",
1089				    &i_rec.inform_info.g_or_v.generic.trap_num);
1090			PARSE_AHEAD(p, net32, " qpn_resp_time_val=0x",
1091				    &i_rec.inform_info.g_or_v.generic.
1092				    qpn_resp_time_val);
1093			PARSE_AHEAD(p, net32, " node_type=0x",
1094				    (uint32_t *) & i_rec.inform_info.g_or_v.
1095				    generic.reserved2);
1096
1097			PARSE_AHEAD(p, net16, " rep_addr: lid=0x",
1098				    &rep_addr.dest_lid);
1099			PARSE_AHEAD(p, net8, " path_bits=0x",
1100				    &rep_addr.path_bits);
1101			PARSE_AHEAD(p, net8, " static_rate=0x",
1102				    &rep_addr.static_rate);
1103			PARSE_AHEAD(p, net32, " remote_qp=0x",
1104				    &rep_addr.addr_type.gsi.remote_qp);
1105			PARSE_AHEAD(p, net32, " remote_qkey=0x",
1106				    &rep_addr.addr_type.gsi.remote_qkey);
1107			PARSE_AHEAD(p, net16, " pkey_ix=0x", &val16);
1108			rep_addr.addr_type.gsi.pkey_ix = cl_ntoh16(val16);
1109			PARSE_AHEAD(p, net8, " sl=0x",
1110				    &rep_addr.addr_type.gsi.service_level);
1111
1112			if (load_infr(p_osm, &i_rec, &rep_addr))
1113				rereg_clients = 1;
1114		}
1115	}
1116
1117	if (!rereg_clients)
1118		p_osm->subn.opt.no_clients_rereg = TRUE;
1119
1120_error:
1121	fclose(file);
1122	return ret;
1123}
1124