xref: /freebsd/contrib/ofed/opensm/opensm/osm_sa.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2014 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 <unistd.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <complib/cl_qmap.h>
56 #include <complib/cl_passivelock.h>
57 #include <complib/cl_debug.h>
58 #include <iba/ib_types.h>
59 #include <opensm/osm_file_ids.h>
60 #define FILE_ID OSM_FILE_SA_C
61 #include <opensm/osm_sa.h>
62 #include <opensm/osm_madw.h>
63 #include <opensm/osm_log.h>
64 #include <opensm/osm_subnet.h>
65 #include <opensm/osm_mad_pool.h>
66 #include <opensm/osm_msgdef.h>
67 #include <opensm/osm_opensm.h>
68 #include <opensm/osm_multicast.h>
69 #include <opensm/osm_inform.h>
70 #include <opensm/osm_service.h>
71 #include <opensm/osm_guid.h>
72 #include <opensm/osm_helper.h>
73 #include <vendor/osm_vendor_api.h>
74 
75 #define  OSM_SA_INITIAL_TID_VALUE 0xabc
76 
77 extern void osm_cpi_rcv_process(IN void *context, IN void *data);
78 extern void osm_gir_rcv_process(IN void *context, IN void *data);
79 extern void osm_infr_rcv_process(IN void *context, IN void *data);
80 extern void osm_infir_rcv_process(IN void *context, IN void *data);
81 extern void osm_lftr_rcv_process(IN void *context, IN void *data);
82 extern void osm_lr_rcv_process(IN void *context, IN void *data);
83 extern void osm_mcmr_rcv_process(IN void *context, IN void *data);
84 extern void osm_mftr_rcv_process(IN void *context, IN void *data);
85 extern void osm_mpr_rcv_process(IN void *context, IN void *data);
86 extern void osm_nr_rcv_process(IN void *context, IN void *data);
87 extern void osm_pr_rcv_process(IN void *context, IN void *data);
88 extern void osm_pkey_rec_rcv_process(IN void *context, IN void *data);
89 extern void osm_pir_rcv_process(IN void *context, IN void *data);
90 extern void osm_sr_rcv_process(IN void *context, IN void *data);
91 extern void osm_slvl_rec_rcv_process(IN void *context, IN void *data);
92 extern void osm_smir_rcv_process(IN void *context, IN void *data);
93 extern void osm_sir_rcv_process(IN void *context, IN void *data);
94 extern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data);
95 extern void osm_sr_rcv_lease_cb(IN void *context);
96 
osm_sa_construct(IN osm_sa_t * p_sa)97 void osm_sa_construct(IN osm_sa_t * p_sa)
98 {
99 	memset(p_sa, 0, sizeof(*p_sa));
100 	p_sa->state = OSM_SA_STATE_INIT;
101 	p_sa->sa_trans_id = OSM_SA_INITIAL_TID_VALUE;
102 
103 	cl_timer_construct(&p_sa->sr_timer);
104 }
105 
osm_sa_shutdown(IN osm_sa_t * p_sa)106 void osm_sa_shutdown(IN osm_sa_t * p_sa)
107 {
108 	OSM_LOG_ENTER(p_sa->p_log);
109 
110 	cl_timer_stop(&p_sa->sr_timer);
111 
112 	/* unbind from the mad service */
113 	osm_sa_mad_ctrl_unbind(&p_sa->mad_ctrl);
114 
115 	/* remove any registered dispatcher message */
116 	cl_disp_unregister(p_sa->nr_disp_h);
117 	cl_disp_unregister(p_sa->pir_disp_h);
118 	cl_disp_unregister(p_sa->gir_disp_h);
119 	cl_disp_unregister(p_sa->lr_disp_h);
120 	cl_disp_unregister(p_sa->pr_disp_h);
121 #if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
122 	cl_disp_unregister(p_sa->mpr_disp_h);
123 #endif
124 	cl_disp_unregister(p_sa->smir_disp_h);
125 	cl_disp_unregister(p_sa->mcmr_disp_h);
126 	cl_disp_unregister(p_sa->sr_disp_h);
127 	cl_disp_unregister(p_sa->infr_disp_h);
128 	cl_disp_unregister(p_sa->infir_disp_h);
129 	cl_disp_unregister(p_sa->vlarb_disp_h);
130 	cl_disp_unregister(p_sa->slvl_disp_h);
131 	cl_disp_unregister(p_sa->pkey_disp_h);
132 	cl_disp_unregister(p_sa->lft_disp_h);
133 	cl_disp_unregister(p_sa->sir_disp_h);
134 	cl_disp_unregister(p_sa->mft_disp_h);
135 
136 	if (p_sa->p_set_disp) {
137 		cl_disp_unregister(p_sa->mcmr_set_disp_h);
138 		cl_disp_unregister(p_sa->infr_set_disp_h);
139 		cl_disp_unregister(p_sa->sr_set_disp_h);
140 		cl_disp_unregister(p_sa->gir_set_disp_h);
141 	}
142 
143 	osm_sa_mad_ctrl_destroy(&p_sa->mad_ctrl);
144 
145 	OSM_LOG_EXIT(p_sa->p_log);
146 }
147 
osm_sa_destroy(IN osm_sa_t * p_sa)148 void osm_sa_destroy(IN osm_sa_t * p_sa)
149 {
150 	OSM_LOG_ENTER(p_sa->p_log);
151 
152 	p_sa->state = OSM_SA_STATE_INIT;
153 
154 	cl_timer_destroy(&p_sa->sr_timer);
155 
156 	OSM_LOG_EXIT(p_sa->p_log);
157 }
158 
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)159 ib_api_status_t osm_sa_init(IN osm_sm_t * p_sm, IN osm_sa_t * p_sa,
160 			    IN osm_subn_t * p_subn, IN osm_vendor_t * p_vendor,
161 			    IN osm_mad_pool_t * p_mad_pool,
162 			    IN osm_log_t * p_log, IN osm_stats_t * p_stats,
163 			    IN cl_dispatcher_t * p_disp,
164 			    IN cl_dispatcher_t * p_set_disp,
165 			    IN cl_plock_t * p_lock)
166 {
167 	ib_api_status_t status;
168 
169 	OSM_LOG_ENTER(p_log);
170 
171 	p_sa->sm = p_sm;
172 	p_sa->p_subn = p_subn;
173 	p_sa->p_vendor = p_vendor;
174 	p_sa->p_mad_pool = p_mad_pool;
175 	p_sa->p_log = p_log;
176 	p_sa->p_disp = p_disp;
177 	p_sa->p_set_disp = p_set_disp;
178 	p_sa->p_lock = p_lock;
179 
180 	p_sa->state = OSM_SA_STATE_READY;
181 
182 	status = osm_sa_mad_ctrl_init(&p_sa->mad_ctrl, p_sa, p_sa->p_mad_pool,
183 				      p_sa->p_vendor, p_subn, p_log, p_stats,
184 				      p_disp, p_set_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 	status = IB_INSUFFICIENT_RESOURCES;
193 	p_sa->cpi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_CLASS_PORT_INFO,
194 					    osm_cpi_rcv_process, p_sa);
195 	if (p_sa->cpi_disp_h == CL_DISP_INVALID_HANDLE)
196 		goto Exit;
197 
198 	p_sa->nr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_RECORD,
199 					   osm_nr_rcv_process, p_sa);
200 	if (p_sa->nr_disp_h == CL_DISP_INVALID_HANDLE)
201 		goto Exit;
202 
203 	p_sa->pir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORTINFO_RECORD,
204 					    osm_pir_rcv_process, p_sa);
205 	if (p_sa->pir_disp_h == CL_DISP_INVALID_HANDLE)
206 		goto Exit;
207 
208 	p_sa->gir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_GUIDINFO_RECORD,
209 					    osm_gir_rcv_process, p_sa);
210 	if (p_sa->gir_disp_h == CL_DISP_INVALID_HANDLE)
211 		goto Exit;
212 
213 	p_sa->lr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LINK_RECORD,
214 					   osm_lr_rcv_process, p_sa);
215 	if (p_sa->lr_disp_h == CL_DISP_INVALID_HANDLE)
216 		goto Exit;
217 
218 	p_sa->pr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PATH_RECORD,
219 					   osm_pr_rcv_process, p_sa);
220 	if (p_sa->pr_disp_h == CL_DISP_INVALID_HANDLE)
221 		goto Exit;
222 
223 #if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
224 	p_sa->mpr_disp_h =
225 	    cl_disp_register(p_disp, OSM_MSG_MAD_MULTIPATH_RECORD,
226 			     osm_mpr_rcv_process, p_sa);
227 	if (p_sa->mpr_disp_h == CL_DISP_INVALID_HANDLE)
228 		goto Exit;
229 #endif
230 
231 	p_sa->smir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SMINFO_RECORD,
232 					     osm_smir_rcv_process, p_sa);
233 	if (p_sa->smir_disp_h == CL_DISP_INVALID_HANDLE)
234 		goto Exit;
235 
236 	p_sa->mcmr_disp_h =
237 	    cl_disp_register(p_disp, OSM_MSG_MAD_MCMEMBER_RECORD,
238 			     osm_mcmr_rcv_process, p_sa);
239 	if (p_sa->mcmr_disp_h == CL_DISP_INVALID_HANDLE)
240 		goto Exit;
241 
242 	p_sa->sr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SERVICE_RECORD,
243 					   osm_sr_rcv_process, p_sa);
244 	if (p_sa->sr_disp_h == CL_DISP_INVALID_HANDLE)
245 		goto Exit;
246 
247 	p_sa->infr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO,
248 					     osm_infr_rcv_process, p_sa);
249 	if (p_sa->infr_disp_h == CL_DISP_INVALID_HANDLE)
250 		goto Exit;
251 
252 	p_sa->infir_disp_h =
253 	    cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO_RECORD,
254 			     osm_infir_rcv_process, p_sa);
255 	if (p_sa->infir_disp_h == CL_DISP_INVALID_HANDLE)
256 		goto Exit;
257 
258 	p_sa->vlarb_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB_RECORD,
259 					      osm_vlarb_rec_rcv_process, p_sa);
260 	if (p_sa->vlarb_disp_h == CL_DISP_INVALID_HANDLE)
261 		goto Exit;
262 
263 	p_sa->slvl_disp_h =
264 	    cl_disp_register(p_disp, OSM_MSG_MAD_SLVL_TBL_RECORD,
265 			     osm_slvl_rec_rcv_process, p_sa);
266 	if (p_sa->slvl_disp_h == CL_DISP_INVALID_HANDLE)
267 		goto Exit;
268 
269 	p_sa->pkey_disp_h =
270 	    cl_disp_register(p_disp, OSM_MSG_MAD_PKEY_TBL_RECORD,
271 			     osm_pkey_rec_rcv_process, p_sa);
272 	if (p_sa->pkey_disp_h == CL_DISP_INVALID_HANDLE)
273 		goto Exit;
274 
275 	p_sa->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT_RECORD,
276 					    osm_lftr_rcv_process, p_sa);
277 	if (p_sa->lft_disp_h == CL_DISP_INVALID_HANDLE)
278 		goto Exit;
279 
280 	p_sa->sir_disp_h =
281 	    cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO_RECORD,
282 			     osm_sir_rcv_process, p_sa);
283 	if (p_sa->sir_disp_h == CL_DISP_INVALID_HANDLE)
284 		goto Exit;
285 
286 	p_sa->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT_RECORD,
287 					    osm_mftr_rcv_process, p_sa);
288 	if (p_sa->mft_disp_h == CL_DISP_INVALID_HANDLE)
289 		goto Exit;
290 
291 	/*
292 	 * When p_set_disp is defined, it means that we use different dispatcher
293 	 * for SA Set requests, and we need to register handlers for it.
294 	 */
295 	if (p_set_disp) {
296 		p_sa->gir_set_disp_h =
297 		    cl_disp_register(p_set_disp, OSM_MSG_MAD_GUIDINFO_RECORD,
298 				     osm_gir_rcv_process, p_sa);
299 		if (p_sa->gir_set_disp_h == CL_DISP_INVALID_HANDLE)
300 			goto Exit;
301 
302 		p_sa->mcmr_set_disp_h =
303 		    cl_disp_register(p_set_disp, OSM_MSG_MAD_MCMEMBER_RECORD,
304 				     osm_mcmr_rcv_process, p_sa);
305 		if (p_sa->mcmr_set_disp_h == CL_DISP_INVALID_HANDLE)
306 			goto Exit;
307 
308 		p_sa->sr_set_disp_h =
309 		    cl_disp_register(p_set_disp, OSM_MSG_MAD_SERVICE_RECORD,
310 				     osm_sr_rcv_process, p_sa);
311 		if (p_sa->sr_set_disp_h == CL_DISP_INVALID_HANDLE)
312 			goto Exit;
313 
314 		p_sa->infr_set_disp_h =
315 		    cl_disp_register(p_set_disp, OSM_MSG_MAD_INFORM_INFO,
316 				     osm_infr_rcv_process, p_sa);
317 		if (p_sa->infr_set_disp_h == CL_DISP_INVALID_HANDLE)
318 			goto Exit;
319 	}
320 
321 	status = IB_SUCCESS;
322 Exit:
323 	OSM_LOG_EXIT(p_log);
324 	return status;
325 }
326 
osm_sa_bind(IN osm_sa_t * p_sa,IN ib_net64_t port_guid)327 ib_api_status_t osm_sa_bind(IN osm_sa_t * p_sa, IN ib_net64_t port_guid)
328 {
329 	ib_api_status_t status;
330 
331 	OSM_LOG_ENTER(p_sa->p_log);
332 
333 	status = osm_sa_mad_ctrl_bind(&p_sa->mad_ctrl, port_guid);
334 
335 	if (status != IB_SUCCESS) {
336 		OSM_LOG(p_sa->p_log, OSM_LOG_ERROR, "ERR 4C03: "
337 			"SA MAD Controller bind failed (%s)\n",
338 			ib_get_err_str(status));
339 		goto Exit;
340 	}
341 
342 Exit:
343 	OSM_LOG_EXIT(p_sa->p_log);
344 	return status;
345 }
346 
osm_sa_send(osm_sa_t * sa,IN osm_madw_t * p_madw,IN boolean_t resp_expected)347 ib_api_status_t osm_sa_send(osm_sa_t *sa, IN osm_madw_t * p_madw,
348 			    IN boolean_t resp_expected)
349 {
350 	ib_api_status_t status;
351 
352 	cl_atomic_inc(&sa->p_subn->p_osm->stats.sa_mads_sent);
353 	status = osm_vendor_send(p_madw->h_bind, p_madw, resp_expected);
354 	if (status != IB_SUCCESS) {
355 		cl_atomic_dec(&sa->p_subn->p_osm->stats.sa_mads_sent);
356 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C04: "
357 			"osm_vendor_send failed, status = %s\n",
358 			ib_get_err_str(status));
359 	}
360 	return status;
361 }
362 
osm_sa_send_error(IN osm_sa_t * sa,IN const osm_madw_t * p_madw,IN ib_net16_t sa_status)363 void osm_sa_send_error(IN osm_sa_t * sa, IN const osm_madw_t * p_madw,
364 		       IN ib_net16_t sa_status)
365 {
366 	osm_madw_t *p_resp_madw;
367 	ib_sa_mad_t *p_resp_sa_mad;
368 	ib_sa_mad_t *p_sa_mad;
369 
370 	OSM_LOG_ENTER(sa->p_log);
371 
372 	/* avoid races - if we are exiting - exit */
373 	if (osm_exit_flag) {
374 		OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
375 			"Ignoring requested send after exit\n");
376 		goto Exit;
377 	}
378 
379 	p_resp_madw = osm_mad_pool_get(sa->p_mad_pool,
380 				       p_madw->h_bind, MAD_BLOCK_SIZE,
381 				       &p_madw->mad_addr);
382 
383 	if (p_resp_madw == NULL) {
384 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C07: "
385 			"Unable to acquire response MAD\n");
386 		goto Exit;
387 	}
388 
389 	p_resp_sa_mad = osm_madw_get_sa_mad_ptr(p_resp_madw);
390 	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
391 
392 	/*  Copy the MAD header back into the response mad */
393 	*p_resp_sa_mad = *p_sa_mad;
394 	p_resp_sa_mad->status = sa_status;
395 
396 	if (p_resp_sa_mad->method == IB_MAD_METHOD_SET)
397 		p_resp_sa_mad->method = IB_MAD_METHOD_GET;
398 	else if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE)
399 		p_resp_sa_mad->attr_offset = 0;
400 
401 	p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
402 
403 	/*
404 	 * C15-0.1.5 - always return SM_Key = 0 (table 185 p 884)
405 	 */
406 	p_resp_sa_mad->sm_key = 0;
407 
408 	/*
409 	 * o15-0.2.7 - The PathRecord Attribute ID shall be used in
410 	 * the response (to a SubnAdmGetMulti(MultiPathRecord)
411 	 */
412 	if (p_resp_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD)
413 		p_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
414 
415 	if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_FRAMES))
416 		osm_dump_sa_mad_v2(sa->p_log, p_resp_sa_mad, FILE_ID, OSM_LOG_FRAMES);
417 
418 	osm_sa_send(sa, p_resp_madw, FALSE);
419 
420 Exit:
421 	OSM_LOG_EXIT(sa->p_log);
422 }
423 
osm_sa_respond(osm_sa_t * sa,osm_madw_t * madw,size_t attr_size,cl_qlist_t * list)424 void osm_sa_respond(osm_sa_t *sa, osm_madw_t *madw, size_t attr_size,
425 		    cl_qlist_t *list)
426 {
427 	cl_list_item_t *item;
428 	osm_madw_t *resp_madw;
429 	ib_sa_mad_t *sa_mad, *resp_sa_mad;
430 	unsigned num_rec, i;
431 #ifndef VENDOR_RMPP_SUPPORT
432 	unsigned trim_num_rec;
433 #endif
434 	unsigned char *p;
435 
436 	sa_mad = osm_madw_get_sa_mad_ptr(madw);
437 	num_rec = cl_qlist_count(list);
438 
439 	/*
440 	 * C15-0.1.30:
441 	 * If we do a SubnAdmGet and got more than one record it is an error!
442 	 */
443 	if (sa_mad->method == IB_MAD_METHOD_GET && num_rec > 1) {
444 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C05: "
445 			"Got %u records for SubnAdmGet(%s) comp_mask 0x%016" PRIx64
446 			"from requester LID %u\n",
447 			num_rec, ib_get_sa_attr_str(sa_mad->attr_id),
448 			cl_ntoh64(sa_mad->comp_mask),
449 			cl_ntoh16(madw->mad_addr.dest_lid));
450 		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_TOO_MANY_RECORDS);
451 		goto Exit;
452 	}
453 
454 #ifndef VENDOR_RMPP_SUPPORT
455 	trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / attr_size;
456 	if (trim_num_rec < num_rec) {
457 		OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
458 			"Number of records:%u trimmed to:%u to fit in one MAD\n",
459 			num_rec, trim_num_rec);
460 		num_rec = trim_num_rec;
461 	}
462 #endif
463 
464 	OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Returning %u records\n", num_rec);
465 
466 	if (sa_mad->method == IB_MAD_METHOD_GET && num_rec == 0) {
467 		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RECORDS);
468 		goto Exit;
469 	}
470 
471 	/*
472 	 * Get a MAD to reply. Address of Mad is in the received mad_wrapper
473 	 */
474 	resp_madw = osm_mad_pool_get(sa->p_mad_pool, madw->h_bind,
475 				     num_rec * attr_size + IB_SA_MAD_HDR_SIZE,
476 				     &madw->mad_addr);
477 	if (!resp_madw) {
478 		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C06: "
479 			"osm_mad_pool_get failed\n");
480 		osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RESOURCES);
481 		goto Exit;
482 	}
483 
484 	resp_sa_mad = osm_madw_get_sa_mad_ptr(resp_madw);
485 
486 	/*
487 	   Copy the MAD header back into the response mad.
488 	   Set the 'R' bit and the payload length,
489 	   Then copy all records from the list into the response payload.
490 	 */
491 
492 	memcpy(resp_sa_mad, sa_mad, IB_SA_MAD_HDR_SIZE);
493 	if (resp_sa_mad->method == IB_MAD_METHOD_SET)
494 		resp_sa_mad->method = IB_MAD_METHOD_GET;
495 	resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
496 	/* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
497 	resp_sa_mad->sm_key = 0;
498 
499 	/* Fill in the offset (paylen will be done by the rmpp SAR) */
500 	resp_sa_mad->attr_offset = num_rec ? ib_get_attr_offset(attr_size) : 0;
501 
502 	p = ib_sa_mad_get_payload_ptr(resp_sa_mad);
503 
504 #ifndef VENDOR_RMPP_SUPPORT
505 	/* we support only one packet RMPP - so we will set the first and
506 	   last flags for gettable */
507 	if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) {
508 		resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;
509 		resp_sa_mad->rmpp_flags =
510 		    IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST |
511 		    IB_RMPP_FLAG_ACTIVE;
512 	}
513 #else
514 	/* forcefully define the packet as RMPP one */
515 	if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
516 		resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
517 #endif
518 
519 	for (i = 0; i < num_rec; i++) {
520 		item = cl_qlist_remove_head(list);
521 		memcpy(p, ((osm_sa_item_t *)item)->resp.data, attr_size);
522 		p += attr_size;
523 		free(item);
524 	}
525 
526 	osm_dump_sa_mad_v2(sa->p_log, resp_sa_mad, FILE_ID, OSM_LOG_FRAMES);
527 	osm_sa_send(sa, resp_madw, FALSE);
528 
529 Exit:
530 	/* need to set the mem free ... */
531 	item = cl_qlist_remove_head(list);
532 	while (item != cl_qlist_end(list)) {
533 		free(item);
534 		item = cl_qlist_remove_head(list);
535 	}
536 }
537 
538 /*
539  *  SA DB Dumper
540  *
541  */
542 
543 struct opensm_dump_context {
544 	osm_opensm_t *p_osm;
545 	FILE *file;
546 };
547 
548 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))549 opensm_dump_to_file(osm_opensm_t * p_osm, const char *file_name,
550 		    void (*dump_func) (osm_opensm_t * p_osm, FILE * file))
551 {
552 	char path[1024];
553 	char path_tmp[1032];
554 	FILE *file;
555 	int fd, status = 0;
556 
557 	snprintf(path, sizeof(path), "%s/%s",
558 		 p_osm->subn.opt.dump_files_dir, file_name);
559 
560 	snprintf(path_tmp, sizeof(path_tmp), "%s.tmp", path);
561 
562 	file = fopen(path_tmp, "w");
563 	if (!file) {
564 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C01: "
565 			"cannot open file \'%s\': %s\n",
566 			path_tmp, strerror(errno));
567 		return -1;
568 	}
569 
570 	if (chmod(path_tmp, S_IRUSR | S_IWUSR)) {
571 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0C: "
572 			"cannot change access permissions of file "
573 			"\'%s\' : %s\n",
574 			path_tmp, strerror(errno));
575 		fclose(file);
576 		return -1;
577 	}
578 
579 	dump_func(p_osm, file);
580 
581 	if (p_osm->subn.opt.fsync_high_avail_files) {
582 		if (fflush(file) == 0) {
583 			fd = fileno(file);
584 			if (fd != -1) {
585 				if (fsync(fd) == -1)
586 					OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
587 						"ERR 4C08: fsync() failed (%s) for %s\n",
588 						strerror(errno), path_tmp);
589 			} else
590 				OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C09: "
591 					"fileno() failed for %s\n", path_tmp);
592 		} else
593 			OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0A: "
594 				"fflush() failed (%s) for %s\n",
595 				strerror(errno), path_tmp);
596 	}
597 
598 	fclose(file);
599 
600 	status = rename(path_tmp, path);
601 	if (status) {
602 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C0B: "
603 			"Failed to rename file:%s (err:%s)\n",
604 			path_tmp, strerror(errno));
605 	}
606 
607 	return status;
608 }
609 
mcast_mgr_dump_one_port(cl_map_item_t * p_map_item,void * cxt)610 static void mcast_mgr_dump_one_port(cl_map_item_t * p_map_item, void *cxt)
611 {
612 	FILE *file = ((struct opensm_dump_context *)cxt)->file;
613 	osm_mcm_alias_guid_t *p_mcm_alias_guid = (osm_mcm_alias_guid_t *) p_map_item;
614 
615 	fprintf(file, "mcm_port: "
616 		"port_gid=0x%016" PRIx64 ":0x%016" PRIx64 " "
617 		"scope_state=0x%02x proxy_join=0x%x" "\n\n",
618 		cl_ntoh64(p_mcm_alias_guid->port_gid.unicast.prefix),
619 		cl_ntoh64(p_mcm_alias_guid->port_gid.unicast.interface_id),
620 		p_mcm_alias_guid->scope_state, p_mcm_alias_guid->proxy_join);
621 }
622 
sa_dump_one_mgrp(osm_mgrp_t * p_mgrp,void * cxt)623 static void sa_dump_one_mgrp(osm_mgrp_t *p_mgrp, void *cxt)
624 {
625 	struct opensm_dump_context dump_context;
626 	osm_opensm_t *p_osm = ((struct opensm_dump_context *)cxt)->p_osm;
627 	FILE *file = ((struct opensm_dump_context *)cxt)->file;
628 
629 	fprintf(file, "MC Group 0x%04x %s:"
630 		" mgid=0x%016" PRIx64 ":0x%016" PRIx64
631 		" port_gid=0x%016" PRIx64 ":0x%016" PRIx64
632 		" qkey=0x%08x mlid=0x%04x mtu=0x%02x tclass=0x%02x"
633 		" pkey=0x%04x rate=0x%02x pkt_life=0x%02x sl_flow_hop=0x%08x"
634 		" scope_state=0x%02x proxy_join=0x%x" "\n\n",
635 		cl_ntoh16(p_mgrp->mlid),
636 		p_mgrp->well_known ? " (well known)" : "",
637 		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix),
638 		cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id),
639 		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.prefix),
640 		cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.interface_id),
641 		cl_ntoh32(p_mgrp->mcmember_rec.qkey),
642 		cl_ntoh16(p_mgrp->mcmember_rec.mlid),
643 		p_mgrp->mcmember_rec.mtu,
644 		p_mgrp->mcmember_rec.tclass,
645 		cl_ntoh16(p_mgrp->mcmember_rec.pkey),
646 		p_mgrp->mcmember_rec.rate,
647 		p_mgrp->mcmember_rec.pkt_life,
648 		cl_ntoh32(p_mgrp->mcmember_rec.sl_flow_hop),
649 		p_mgrp->mcmember_rec.scope_state,
650 		p_mgrp->mcmember_rec.proxy_join);
651 
652 	dump_context.p_osm = p_osm;
653 	dump_context.file = file;
654 
655 	cl_qmap_apply_func(&p_mgrp->mcm_alias_port_tbl,
656 			   mcast_mgr_dump_one_port, &dump_context);
657 }
658 
sa_dump_one_inform(cl_list_item_t * p_list_item,void * cxt)659 static void sa_dump_one_inform(cl_list_item_t * p_list_item, void *cxt)
660 {
661 	FILE *file = ((struct opensm_dump_context *)cxt)->file;
662 	osm_infr_t *p_infr = (osm_infr_t *) p_list_item;
663 	ib_inform_info_record_t *p_iir = &p_infr->inform_record;
664 
665 	fprintf(file, "InformInfo Record:"
666 		" subscriber_gid=0x%016" PRIx64 ":0x%016" PRIx64
667 		" subscriber_enum=0x%x"
668 		" InformInfo:"
669 		" gid=0x%016" PRIx64 ":0x%016" PRIx64
670 		" lid_range_begin=0x%x"
671 		" lid_range_end=0x%x"
672 		" is_generic=0x%x"
673 		" subscribe=0x%x"
674 		" trap_type=0x%x"
675 		" trap_num=0x%x"
676 		" qpn_resp_time_val=0x%x"
677 		" node_type=0x%06x"
678 		" rep_addr: lid=0x%04x path_bits=0x%02x static_rate=0x%02x"
679 		" remote_qp=0x%08x remote_qkey=0x%08x pkey_ix=0x%04x sl=0x%02x"
680 		"\n\n",
681 		cl_ntoh64(p_iir->subscriber_gid.unicast.prefix),
682 		cl_ntoh64(p_iir->subscriber_gid.unicast.interface_id),
683 		cl_ntoh16(p_iir->subscriber_enum),
684 		cl_ntoh64(p_iir->inform_info.gid.unicast.prefix),
685 		cl_ntoh64(p_iir->inform_info.gid.unicast.interface_id),
686 		cl_ntoh16(p_iir->inform_info.lid_range_begin),
687 		cl_ntoh16(p_iir->inform_info.lid_range_end),
688 		p_iir->inform_info.is_generic,
689 		p_iir->inform_info.subscribe,
690 		cl_ntoh16(p_iir->inform_info.trap_type),
691 		cl_ntoh16(p_iir->inform_info.g_or_v.generic.trap_num),
692 		cl_ntoh32(p_iir->inform_info.g_or_v.generic.qpn_resp_time_val),
693 		cl_ntoh32(ib_inform_info_get_prod_type(&p_iir->inform_info)),
694 		cl_ntoh16(p_infr->report_addr.dest_lid),
695 		p_infr->report_addr.path_bits,
696 		p_infr->report_addr.static_rate,
697 		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qp),
698 		cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qkey),
699 		p_infr->report_addr.addr_type.gsi.pkey_ix,
700 		p_infr->report_addr.addr_type.gsi.service_level);
701 }
702 
sa_dump_one_service(cl_list_item_t * p_list_item,void * cxt)703 static void sa_dump_one_service(cl_list_item_t * p_list_item, void *cxt)
704 {
705 	FILE *file = ((struct opensm_dump_context *)cxt)->file;
706 	osm_svcr_t *p_svcr = (osm_svcr_t *) p_list_item;
707 	ib_service_record_t *p_sr = &p_svcr->service_record;
708 
709 	fprintf(file, "Service Record: id=0x%016" PRIx64
710 		" gid=0x%016" PRIx64 ":0x%016" PRIx64
711 		" pkey=0x%x"
712 		" lease=0x%x"
713 		" key=0x%02x%02x%02x%02x%02x%02x%02x%02x"
714 		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
715 		" name=\'%s\'"
716 		" data8=0x%02x%02x%02x%02x%02x%02x%02x%02x"
717 		":0x%02x%02x%02x%02x%02x%02x%02x%02x"
718 		" data16=0x%04x%04x%04x%04x:0x%04x%04x%04x%04x"
719 		" data32=0x%08x%08x:0x%08x%08x"
720 		" data64=0x%016" PRIx64 ":0x%016" PRIx64
721 		" modified_time=0x%x lease_period=0x%x\n\n",
722 		cl_ntoh64(p_sr->service_id),
723 		cl_ntoh64(p_sr->service_gid.unicast.prefix),
724 		cl_ntoh64(p_sr->service_gid.unicast.interface_id),
725 		cl_ntoh16(p_sr->service_pkey),
726 		cl_ntoh32(p_sr->service_lease),
727 		p_sr->service_key[0], p_sr->service_key[1],
728 		p_sr->service_key[2], p_sr->service_key[3],
729 		p_sr->service_key[4], p_sr->service_key[5],
730 		p_sr->service_key[6], p_sr->service_key[7],
731 		p_sr->service_key[8], p_sr->service_key[9],
732 		p_sr->service_key[10], p_sr->service_key[11],
733 		p_sr->service_key[12], p_sr->service_key[13],
734 		p_sr->service_key[14], p_sr->service_key[15],
735 		p_sr->service_name,
736 		p_sr->service_data8[0], p_sr->service_data8[1],
737 		p_sr->service_data8[2], p_sr->service_data8[3],
738 		p_sr->service_data8[4], p_sr->service_data8[5],
739 		p_sr->service_data8[6], p_sr->service_data8[7],
740 		p_sr->service_data8[8], p_sr->service_data8[9],
741 		p_sr->service_data8[10], p_sr->service_data8[11],
742 		p_sr->service_data8[12], p_sr->service_data8[13],
743 		p_sr->service_data8[14], p_sr->service_data8[15],
744 		cl_ntoh16(p_sr->service_data16[0]),
745 		cl_ntoh16(p_sr->service_data16[1]),
746 		cl_ntoh16(p_sr->service_data16[2]),
747 		cl_ntoh16(p_sr->service_data16[3]),
748 		cl_ntoh16(p_sr->service_data16[4]),
749 		cl_ntoh16(p_sr->service_data16[5]),
750 		cl_ntoh16(p_sr->service_data16[6]),
751 		cl_ntoh16(p_sr->service_data16[7]),
752 		cl_ntoh32(p_sr->service_data32[0]),
753 		cl_ntoh32(p_sr->service_data32[1]),
754 		cl_ntoh32(p_sr->service_data32[2]),
755 		cl_ntoh32(p_sr->service_data32[3]),
756 		cl_ntoh64(p_sr->service_data64[0]),
757 		cl_ntoh64(p_sr->service_data64[1]),
758 		p_svcr->modified_time, p_svcr->lease_period);
759 }
760 
sa_dump_one_port_guidinfo(cl_map_item_t * p_map_item,void * cxt)761 static void sa_dump_one_port_guidinfo(cl_map_item_t * p_map_item, void *cxt)
762 {
763 	FILE *file = ((struct opensm_dump_context *)cxt)->file;
764 	osm_port_t *p_port = (osm_port_t *) p_map_item;
765 	uint32_t max_block;
766 	int block_num;
767 
768 	if (!p_port->p_physp->p_guids)
769 		return;
770 
771 	max_block = (p_port->p_physp->port_info.guid_cap + GUID_TABLE_MAX_ENTRIES - 1) /
772 		     GUID_TABLE_MAX_ENTRIES;
773 
774 	for (block_num = 0; block_num < max_block; block_num++) {
775 		fprintf(file, "GUIDInfo Record:"
776 			" base_guid=0x%016" PRIx64 " lid=0x%04x block_num=0x%x"
777 			" guid0=0x%016" PRIx64 " guid1=0x%016" PRIx64
778 			" guid2=0x%016" PRIx64 " guid3=0x%016" PRIx64
779 			" guid4=0x%016" PRIx64 " guid5=0x%016" PRIx64
780 			" guid6=0x%016" PRIx64 " guid7=0x%016" PRIx64
781 			"\n\n",
782 			cl_ntoh64((*p_port->p_physp->p_guids)[0]),
783 			cl_ntoh16(osm_port_get_base_lid(p_port)), block_num,
784 			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES]),
785 			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 1]),
786 			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 2]),
787 			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 3]),
788 			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 4]),
789 			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 5]),
790 			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 6]),
791 			cl_ntoh64((*p_port->p_physp->p_guids)[block_num * GUID_TABLE_MAX_ENTRIES + 7]));
792 	}
793 }
794 
sa_dump_all_sa(osm_opensm_t * p_osm,FILE * file)795 static void sa_dump_all_sa(osm_opensm_t * p_osm, FILE * file)
796 {
797 	struct opensm_dump_context dump_context;
798 	osm_mgrp_t *p_mgrp;
799 
800 	dump_context.p_osm = p_osm;
801 	dump_context.file = file;
802 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump guidinfo\n");
803 	cl_qmap_apply_func(&p_osm->subn.port_guid_tbl,
804 			   sa_dump_one_port_guidinfo, &dump_context);
805 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump multicast\n");
806 	for (p_mgrp = (osm_mgrp_t *) cl_fmap_head(&p_osm->subn.mgrp_mgid_tbl);
807 	     p_mgrp != (osm_mgrp_t *) cl_fmap_end(&p_osm->subn.mgrp_mgid_tbl);
808 	     p_mgrp = (osm_mgrp_t *) cl_fmap_next(&p_mgrp->map_item))
809 		sa_dump_one_mgrp(p_mgrp, &dump_context);
810 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump inform\n");
811 	cl_qlist_apply_func(&p_osm->subn.sa_infr_list,
812 			    sa_dump_one_inform, &dump_context);
813 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump services\n");
814 	cl_qlist_apply_func(&p_osm->subn.sa_sr_list,
815 			    sa_dump_one_service, &dump_context);
816 }
817 
osm_sa_db_file_dump(osm_opensm_t * p_osm)818 int osm_sa_db_file_dump(osm_opensm_t * p_osm)
819 {
820 	int res = 1;
821 
822 	cl_plock_acquire(&p_osm->lock);
823 	if (p_osm->sa.dirty) {
824 		res = opensm_dump_to_file(
825 			p_osm, "opensm-sa.dump", sa_dump_all_sa);
826 		if (!res)
827 			p_osm->sa.dirty = FALSE;
828 	}
829 	cl_plock_release(&p_osm->lock);
830 
831 	return res;
832 }
833 
834 /*
835  *  SA DB Loader
836  */
load_mcgroup(osm_opensm_t * p_osm,ib_net16_t mlid,ib_member_rec_t * p_mcm_rec)837 static osm_mgrp_t *load_mcgroup(osm_opensm_t * p_osm, ib_net16_t mlid,
838 				ib_member_rec_t * p_mcm_rec)
839 {
840 	ib_net64_t comp_mask;
841 	osm_mgrp_t *p_mgrp;
842 
843 	cl_plock_excl_acquire(&p_osm->lock);
844 
845 	p_mgrp = osm_get_mgrp_by_mgid(&p_osm->subn, &p_mcm_rec->mgid);
846 	if (p_mgrp) {
847 		if (p_mgrp->mlid == mlid) {
848 			OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
849 				"mgrp %04x is already here.", cl_ntoh16(mlid));
850 			goto _out;
851 		}
852 		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
853 			"mlid %04x is already used by another MC group. Will "
854 			"request clients reregistration.\n", cl_ntoh16(mlid));
855 		p_mgrp = NULL;
856 		goto _out;
857 	}
858 
859 	comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL
860 	    | IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL;
861 	if (!(p_mgrp = osm_mcmr_rcv_find_or_create_new_mgrp(&p_osm->sa,
862 							    comp_mask,
863 							    p_mcm_rec)) ||
864 	    p_mgrp->mlid != mlid) {
865 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
866 			"cannot create MC group with mlid 0x%04x and mgid "
867 			"0x%016" PRIx64 ":0x%016" PRIx64 "\n", cl_ntoh16(mlid),
868 			cl_ntoh64(p_mcm_rec->mgid.unicast.prefix),
869 			cl_ntoh64(p_mcm_rec->mgid.unicast.interface_id));
870 		p_mgrp = NULL;
871 	}
872 
873 _out:
874 	cl_plock_release(&p_osm->lock);
875 
876 	return p_mgrp;
877 }
878 
load_svcr(osm_opensm_t * p_osm,ib_service_record_t * sr,uint32_t modified_time,uint32_t lease_period)879 static int load_svcr(osm_opensm_t * p_osm, ib_service_record_t * sr,
880 		     uint32_t modified_time, uint32_t lease_period)
881 {
882 	osm_svcr_t *p_svcr;
883 	int ret = 0;
884 
885 	cl_plock_excl_acquire(&p_osm->lock);
886 
887 	if (osm_svcr_get_by_rid(&p_osm->subn, &p_osm->log, sr)) {
888 		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
889 			"ServiceRecord already exists\n");
890 		goto _out;
891 	}
892 
893 	if (!(p_svcr = osm_svcr_new(sr))) {
894 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
895 			"cannot allocate new service struct\n");
896 		ret = -1;
897 		goto _out;
898 	}
899 
900 	p_svcr->modified_time = modified_time;
901 	p_svcr->lease_period = lease_period;
902 
903 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding ServiceRecord...\n");
904 
905 	osm_svcr_insert_to_db(&p_osm->subn, &p_osm->log, p_svcr);
906 
907 	if (lease_period != 0xffffffff)
908 		cl_timer_trim(&p_osm->sa.sr_timer, 1000);
909 
910 _out:
911 	cl_plock_release(&p_osm->lock);
912 
913 	return ret;
914 }
915 
load_infr(osm_opensm_t * p_osm,ib_inform_info_record_t * iir,osm_mad_addr_t * addr)916 static int load_infr(osm_opensm_t * p_osm, ib_inform_info_record_t * iir,
917 		     osm_mad_addr_t * addr)
918 {
919 	osm_infr_t infr, *p_infr;
920 	int ret = 0;
921 
922 	infr.h_bind = p_osm->sa.mad_ctrl.h_bind;
923 	infr.sa = &p_osm->sa;
924 	/* other possible way to restore mad_addr partially is
925 	   to extract qpn from InformInfo and to find lid by gid */
926 	infr.report_addr = *addr;
927 	infr.inform_record = *iir;
928 
929 	cl_plock_excl_acquire(&p_osm->lock);
930 	if (osm_infr_get_by_rec(&p_osm->subn, &p_osm->log, &infr)) {
931 		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
932 			"InformInfo Record already exists\n");
933 		goto _out;
934 	}
935 
936 	if (!(p_infr = osm_infr_new(&infr))) {
937 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
938 			"cannot allocate new infr struct\n");
939 		ret = -1;
940 		goto _out;
941 	}
942 
943 	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding InformInfo Record...\n");
944 
945 	osm_infr_insert_to_db(&p_osm->subn, &p_osm->log, p_infr);
946 
947 _out:
948 	cl_plock_release(&p_osm->lock);
949 
950 	return ret;
951 }
952 
load_guidinfo(osm_opensm_t * p_osm,ib_net64_t base_guid,ib_guidinfo_record_t * gir)953 static int load_guidinfo(osm_opensm_t * p_osm, ib_net64_t base_guid,
954 			 ib_guidinfo_record_t *gir)
955 {
956 	osm_port_t *p_port;
957 	uint32_t max_block;
958 	int i, ret = 0;
959 	osm_alias_guid_t *p_alias_guid, *p_alias_guid_check;
960 
961 	cl_plock_excl_acquire(&p_osm->lock);
962 
963 	p_port = osm_get_port_by_guid(&p_osm->subn, base_guid);
964 	if (!p_port)
965 		goto _out;
966 
967 	if (!p_port->p_physp->p_guids) {
968 		max_block = (p_port->p_physp->port_info.guid_cap + GUID_TABLE_MAX_ENTRIES - 1) /
969 			     GUID_TABLE_MAX_ENTRIES;
970 		p_port->p_physp->p_guids = calloc(max_block * GUID_TABLE_MAX_ENTRIES,
971 						  sizeof(ib_net64_t));
972 		if (!p_port->p_physp->p_guids) {
973 			OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
974 				"cannot allocate GUID table for port "
975 				"GUID 0x%" PRIx64 "\n",
976 				cl_ntoh64(p_port->p_physp->port_guid));
977 			goto _out;
978 		}
979 	}
980 
981 	for (i = 0; i < GUID_TABLE_MAX_ENTRIES; i++) {
982 		if (!gir->guid_info.guid[i])
983 			continue;
984 		/* skip block 0 index 0 */
985 		if (gir->block_num == 0 && i == 0)
986 			continue;
987 		if (gir->block_num * GUID_TABLE_MAX_ENTRIES + i >
988 		    p_port->p_physp->port_info.guid_cap)
989 			break;
990 
991 		p_alias_guid = osm_alias_guid_new(gir->guid_info.guid[i],
992 						  p_port);
993 		if (!p_alias_guid) {
994 			OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
995 				"Alias guid %d memory allocation failed"
996 				" for port GUID 0x%" PRIx64 "\n",
997 				gir->block_num * GUID_TABLE_MAX_ENTRIES + i,
998 				cl_ntoh64(p_port->p_physp->port_guid));
999 			goto _out;
1000 		}
1001 
1002 		p_alias_guid_check =
1003 			(osm_alias_guid_t *) cl_qmap_insert(&p_osm->subn.alias_port_guid_tbl,
1004 							    p_alias_guid->alias_guid,
1005 							    &p_alias_guid->map_item);
1006 		if (p_alias_guid_check != p_alias_guid) {
1007 			/* alias GUID is a duplicate */
1008 			OSM_LOG(&p_osm->log, OSM_LOG_ERROR,
1009 				"Duplicate alias port GUID 0x%" PRIx64
1010 				" index %d base port GUID 0x%" PRIx64 "\n",
1011 				cl_ntoh64(p_alias_guid->alias_guid),
1012 				gir->block_num * GUID_TABLE_MAX_ENTRIES + i,
1013 				cl_ntoh64(p_alias_guid->p_base_port->guid));
1014 			osm_alias_guid_delete(&p_alias_guid);
1015 			goto _out;
1016 		}
1017 	}
1018 
1019 	memcpy(&(*p_port->p_physp->p_guids)[gir->block_num * GUID_TABLE_MAX_ENTRIES],
1020 	       &gir->guid_info, sizeof(ib_guid_info_t));
1021 
1022 	osm_queue_guidinfo(&p_osm->sa, p_port, gir->block_num);
1023 
1024 _out:
1025 	cl_plock_release(&p_osm->lock);
1026 
1027 	return ret;
1028 }
1029 
1030 #define UNPACK_FUNC(name,x) \
1031 static int unpack_##name##x(char *p, uint##x##_t *val_ptr) \
1032 { \
1033 	char *q; \
1034 	unsigned long long num; \
1035 	num = strtoull(p, &q, 16); \
1036 	if (num > ~((uint##x##_t)0x0) \
1037 	    || q == p || (!isspace(*q) && *q != ':')) { \
1038 		*val_ptr = 0; \
1039 		return -1; \
1040 	} \
1041 	*val_ptr = cl_hton##x((uint##x##_t)num); \
1042 	return (int)(q - p); \
1043 }
1044 
1045 #define cl_hton8(x) (x)
1046 
1047 UNPACK_FUNC(net, 8);
1048 UNPACK_FUNC(net, 16);
1049 UNPACK_FUNC(net, 32);
1050 UNPACK_FUNC(net, 64);
1051 
unpack_string(char * p,uint8_t * buf,unsigned len)1052 static int unpack_string(char *p, uint8_t * buf, unsigned len)
1053 {
1054 	char *q = p;
1055 	char delim = ' ';
1056 
1057 	if (*q == '\'' || *q == '\"')
1058 		delim = *q++;
1059 	while (--len && *q && *q != delim)
1060 		*buf++ = *q++;
1061 	*buf = '\0';
1062 	if (*q == delim && delim != ' ')
1063 		q++;
1064 	return (int)(q - p);
1065 }
1066 
unpack_string64(char * p,uint8_t * buf)1067 static int unpack_string64(char *p, uint8_t * buf)
1068 {
1069 	return unpack_string(p, buf, 64);
1070 }
1071 
1072 #define PARSE_AHEAD(p, x, name, val_ptr) { int _ret; \
1073 	p = strstr(p, name); \
1074 	if (!p) { \
1075 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \
1076 			"PARSE ERROR: %s:%u: cannot find \"%s\" string\n", \
1077 			file_name, lineno, (name)); \
1078 		ret = -2; \
1079 		goto _error; \
1080 	} \
1081 	p += strlen(name); \
1082 	_ret = unpack_##x(p, (val_ptr)); \
1083 	if (_ret < 0) { \
1084 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \
1085 			"PARSE ERROR: %s:%u: cannot parse "#x" value " \
1086 			"after \"%s\"\n", file_name, lineno, (name)); \
1087 		ret = _ret; \
1088 		goto _error; \
1089 	} \
1090 	p += _ret; \
1091 }
1092 
sa_db_file_load_handle_mgrp(osm_opensm_t * p_osm,osm_mgrp_t * p_mgrp)1093 static void sa_db_file_load_handle_mgrp(osm_opensm_t * p_osm,
1094 					osm_mgrp_t * p_mgrp)
1095 {
1096 	/* decide whether to delete the mgrp object or not */
1097 	if (p_mgrp->full_members == 0 && !p_mgrp->well_known) {
1098 		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
1099 			"Closing MC group 0x%016" PRIx64 ":0x%016" PRIx64
1100 			" - no full members were added to not well known "
1101 			"group\n",
1102 			cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix),
1103 			cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id));
1104 		osm_mgrp_cleanup(&p_osm->subn, p_mgrp);
1105 	}
1106 }
1107 
osm_sa_db_file_load(osm_opensm_t * p_osm)1108 int osm_sa_db_file_load(osm_opensm_t * p_osm)
1109 {
1110 	char line[1024];
1111 	char *file_name;
1112 	FILE *file;
1113 	int ret = 0;
1114 	osm_mgrp_t *p_next_mgrp = NULL;
1115 	osm_mgrp_t *p_prev_mgrp = NULL;
1116 	unsigned rereg_clients = 0;
1117 	unsigned lineno;
1118 
1119 	if (!p_osm->subn.first_time_master_sweep) {
1120 		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
1121 			"Not first sweep - skip SA DB restore\n");
1122 		return 0;
1123 	}
1124 
1125 	file_name = p_osm->subn.opt.sa_db_file;
1126 	if (!file_name) {
1127 		OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
1128 			"sa db file name is not specified. Skip restore\n");
1129 		return 0;
1130 	}
1131 
1132 	file = fopen(file_name, "r");
1133 	if (!file) {
1134 		OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 4C02: "
1135 			"Can't open sa db file \'%s\'. Skip restoring\n",
1136 			file_name);
1137 		return -1;
1138 	}
1139 
1140 	OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
1141 		"Restoring SA DB from file \'%s\'\n",
1142 		file_name);
1143 
1144 	lineno = 0;
1145 
1146 	while (fgets(line, sizeof(line) - 1, file) != NULL) {
1147 		char *p;
1148 		uint8_t val;
1149 
1150 		lineno++;
1151 
1152 		p = line;
1153 		while (isspace(*p))
1154 			p++;
1155 
1156 		if (*p == '#')
1157 			continue;
1158 
1159 		if (!strncmp(p, "MC Group", 8)) {
1160 			ib_member_rec_t mcm_rec;
1161 			ib_net16_t mlid;
1162 
1163 			p_next_mgrp = NULL;
1164 			memset(&mcm_rec, 0, sizeof(mcm_rec));
1165 
1166 			PARSE_AHEAD(p, net16, " 0x", &mlid);
1167 			PARSE_AHEAD(p, net64, " mgid=0x",
1168 				    &mcm_rec.mgid.unicast.prefix);
1169 			PARSE_AHEAD(p, net64, ":0x",
1170 				    &mcm_rec.mgid.unicast.interface_id);
1171 			PARSE_AHEAD(p, net64, " port_gid=0x",
1172 				    &mcm_rec.port_gid.unicast.prefix);
1173 			PARSE_AHEAD(p, net64, ":0x",
1174 				    &mcm_rec.port_gid.unicast.interface_id);
1175 			PARSE_AHEAD(p, net32, " qkey=0x", &mcm_rec.qkey);
1176 			PARSE_AHEAD(p, net16, " mlid=0x", &mcm_rec.mlid);
1177 			PARSE_AHEAD(p, net8, " mtu=0x", &mcm_rec.mtu);
1178 			PARSE_AHEAD(p, net8, " tclass=0x", &mcm_rec.tclass);
1179 			PARSE_AHEAD(p, net16, " pkey=0x", &mcm_rec.pkey);
1180 			PARSE_AHEAD(p, net8, " rate=0x", &mcm_rec.rate);
1181 			PARSE_AHEAD(p, net8, " pkt_life=0x", &mcm_rec.pkt_life);
1182 			PARSE_AHEAD(p, net32, " sl_flow_hop=0x",
1183 				    &mcm_rec.sl_flow_hop);
1184 			PARSE_AHEAD(p, net8, " scope_state=0x",
1185 				    &mcm_rec.scope_state);
1186 			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
1187 			mcm_rec.proxy_join = val;
1188 
1189 			p_next_mgrp = load_mcgroup(p_osm, mlid, &mcm_rec);
1190 			if (!p_next_mgrp)
1191 				rereg_clients = 1;
1192 			if (cl_ntoh16(mlid) > p_osm->sm.mlids_init_max)
1193 				p_osm->sm.mlids_init_max = cl_ntoh16(mlid);
1194 		} else if (p_next_mgrp && !strncmp(p, "mcm_port", 8)) {
1195 			ib_member_rec_t mcmr;
1196 			ib_net64_t guid;
1197 			osm_port_t *port;
1198 			boolean_t proxy;
1199 
1200 			PARSE_AHEAD(p, net64, " port_gid=0x",
1201 				    &mcmr.port_gid.unicast.prefix);
1202 			PARSE_AHEAD(p, net64, ":0x",
1203 				    &mcmr.port_gid.unicast.interface_id);
1204 			PARSE_AHEAD(p, net8, " scope_state=0x", &mcmr.scope_state);
1205 			PARSE_AHEAD(p, net8, " proxy_join=0x", &val);
1206 			proxy = val;
1207 
1208 			guid = mcmr.port_gid.unicast.interface_id;
1209 			port = osm_get_port_by_alias_guid(&p_osm->subn, guid);
1210 			if (port &&
1211 			    cl_qmap_get(&p_next_mgrp->mcm_port_tbl, guid) ==
1212 			    cl_qmap_end(&p_next_mgrp->mcm_port_tbl) &&
1213 			    !osm_mgrp_add_port(&p_osm->subn, &p_osm->log,
1214 						p_next_mgrp, port, &mcmr, proxy))
1215 				rereg_clients = 1;
1216 		} else if (!strncmp(p, "Service Record:", 15)) {
1217 			ib_service_record_t s_rec;
1218 			uint32_t modified_time, lease_period;
1219 
1220 			p_next_mgrp = NULL;
1221 			memset(&s_rec, 0, sizeof(s_rec));
1222 
1223 			PARSE_AHEAD(p, net64, " id=0x", &s_rec.service_id);
1224 			PARSE_AHEAD(p, net64, " gid=0x",
1225 				    &s_rec.service_gid.unicast.prefix);
1226 			PARSE_AHEAD(p, net64, ":0x",
1227 				    &s_rec.service_gid.unicast.interface_id);
1228 			PARSE_AHEAD(p, net16, " pkey=0x", &s_rec.service_pkey);
1229 			PARSE_AHEAD(p, net32, " lease=0x",
1230 				    &s_rec.service_lease);
1231 			PARSE_AHEAD(p, net64, " key=0x",
1232 				    (ib_net64_t *) (&s_rec.service_key[0]));
1233 			PARSE_AHEAD(p, net64, ":0x",
1234 				    (ib_net64_t *) (&s_rec.service_key[8]));
1235 			PARSE_AHEAD(p, string64, " name=", s_rec.service_name);
1236 			PARSE_AHEAD(p, net64, " data8=0x",
1237 				    (ib_net64_t *) (&s_rec.service_data8[0]));
1238 			PARSE_AHEAD(p, net64, ":0x",
1239 				    (ib_net64_t *) (&s_rec.service_data8[8]));
1240 			PARSE_AHEAD(p, net64, " data16=0x",
1241 				    (ib_net64_t *) (&s_rec.service_data16[0]));
1242 			PARSE_AHEAD(p, net64, ":0x",
1243 				    (ib_net64_t *) (&s_rec.service_data16[4]));
1244 			PARSE_AHEAD(p, net64, " data32=0x",
1245 				    (ib_net64_t *) (&s_rec.service_data32[0]));
1246 			PARSE_AHEAD(p, net64, ":0x",
1247 				    (ib_net64_t *) (&s_rec.service_data32[2]));
1248 			PARSE_AHEAD(p, net64, " data64=0x",
1249 				    &s_rec.service_data64[0]);
1250 			PARSE_AHEAD(p, net64, ":0x", &s_rec.service_data64[1]);
1251 			PARSE_AHEAD(p, net32, " modified_time=0x",
1252 				    &modified_time);
1253 			PARSE_AHEAD(p, net32, " lease_period=0x",
1254 				    &lease_period);
1255 
1256 			if (load_svcr(p_osm, &s_rec, cl_ntoh32(modified_time),
1257 				      cl_ntoh32(lease_period)))
1258 				rereg_clients = 1;
1259 		} else if (!strncmp(p, "InformInfo Record:", 18)) {
1260 			ib_inform_info_record_t i_rec;
1261 			osm_mad_addr_t rep_addr;
1262 			ib_net16_t val16;
1263 
1264 			p_next_mgrp = NULL;
1265 			memset(&i_rec, 0, sizeof(i_rec));
1266 			memset(&rep_addr, 0, sizeof(rep_addr));
1267 
1268 			PARSE_AHEAD(p, net64, " subscriber_gid=0x",
1269 				    &i_rec.subscriber_gid.unicast.prefix);
1270 			PARSE_AHEAD(p, net64, ":0x",
1271 				    &i_rec.subscriber_gid.unicast.interface_id);
1272 			PARSE_AHEAD(p, net16, " subscriber_enum=0x",
1273 				    &i_rec.subscriber_enum);
1274 			PARSE_AHEAD(p, net64, " gid=0x",
1275 				    &i_rec.inform_info.gid.unicast.prefix);
1276 			PARSE_AHEAD(p, net64, ":0x",
1277 				    &i_rec.inform_info.gid.unicast.
1278 				    interface_id);
1279 			PARSE_AHEAD(p, net16, " lid_range_begin=0x",
1280 				    &i_rec.inform_info.lid_range_begin);
1281 			PARSE_AHEAD(p, net16, " lid_range_end=0x",
1282 				    &i_rec.inform_info.lid_range_end);
1283 			PARSE_AHEAD(p, net8, " is_generic=0x",
1284 				    &i_rec.inform_info.is_generic);
1285 			PARSE_AHEAD(p, net8, " subscribe=0x",
1286 				    &i_rec.inform_info.subscribe);
1287 			PARSE_AHEAD(p, net16, " trap_type=0x",
1288 				    &i_rec.inform_info.trap_type);
1289 			PARSE_AHEAD(p, net16, " trap_num=0x",
1290 				    &i_rec.inform_info.g_or_v.generic.trap_num);
1291 			PARSE_AHEAD(p, net32, " qpn_resp_time_val=0x",
1292 				    &i_rec.inform_info.g_or_v.generic.
1293 				    qpn_resp_time_val);
1294 			PARSE_AHEAD(p, net32, " node_type=0x",
1295 				    (uint32_t *) & i_rec.inform_info.g_or_v.
1296 				    generic.reserved2);
1297 
1298 			PARSE_AHEAD(p, net16, " rep_addr: lid=0x",
1299 				    &rep_addr.dest_lid);
1300 			PARSE_AHEAD(p, net8, " path_bits=0x",
1301 				    &rep_addr.path_bits);
1302 			PARSE_AHEAD(p, net8, " static_rate=0x",
1303 				    &rep_addr.static_rate);
1304 			PARSE_AHEAD(p, net32, " remote_qp=0x",
1305 				    &rep_addr.addr_type.gsi.remote_qp);
1306 			PARSE_AHEAD(p, net32, " remote_qkey=0x",
1307 				    &rep_addr.addr_type.gsi.remote_qkey);
1308 			PARSE_AHEAD(p, net16, " pkey_ix=0x", &val16);
1309 			rep_addr.addr_type.gsi.pkey_ix = cl_ntoh16(val16);
1310 			PARSE_AHEAD(p, net8, " sl=0x",
1311 				    &rep_addr.addr_type.gsi.service_level);
1312 
1313 			if (load_infr(p_osm, &i_rec, &rep_addr))
1314 				rereg_clients = 1;
1315 		} else if (!strncmp(p, "GUIDInfo Record:", 16)) {
1316 			ib_guidinfo_record_t gi_rec;
1317 			ib_net64_t base_guid;
1318 
1319 			p_next_mgrp = NULL;
1320 			memset(&gi_rec, 0, sizeof(gi_rec));
1321 
1322 			PARSE_AHEAD(p, net64, " base_guid=0x", &base_guid);
1323 			PARSE_AHEAD(p, net16, " lid=0x", &gi_rec.lid);
1324 			PARSE_AHEAD(p, net8, " block_num=0x",
1325 				    &gi_rec.block_num);
1326 			PARSE_AHEAD(p, net64, " guid0=0x",
1327 				    &gi_rec.guid_info.guid[0]);
1328 			PARSE_AHEAD(p, net64, " guid1=0x",
1329 				    &gi_rec.guid_info.guid[1]);
1330 			PARSE_AHEAD(p, net64, " guid2=0x",
1331 				    &gi_rec.guid_info.guid[2]);
1332 			PARSE_AHEAD(p, net64, " guid3=0x",
1333 				    &gi_rec.guid_info.guid[3]);
1334 			PARSE_AHEAD(p, net64, " guid4=0x",
1335 				    &gi_rec.guid_info.guid[4]);
1336 			PARSE_AHEAD(p, net64, " guid5=0x",
1337 				    &gi_rec.guid_info.guid[5]);
1338 			PARSE_AHEAD(p, net64, " guid6=0x",
1339 				    &gi_rec.guid_info.guid[6]);
1340 			PARSE_AHEAD(p, net64, " guid7=0x",
1341 				    &gi_rec.guid_info.guid[7]);
1342 
1343 			if (load_guidinfo(p_osm, base_guid, &gi_rec))
1344 				rereg_clients = 1;
1345 		}
1346 
1347 		/*
1348 		 * p_next_mgrp points to the multicast group now being parsed.
1349 		 * p_prev_mgrp points to the last multicast group we parsed.
1350 		 * We decide whether to keep or delete each multicast group
1351 		 * only when we finish parsing it's member records. if the
1352 		 * group has full members, or it is a "well known group" we
1353 		 * keep it.
1354 		 */
1355 		if (p_prev_mgrp != p_next_mgrp) {
1356 			if (p_prev_mgrp)
1357 				sa_db_file_load_handle_mgrp(p_osm, p_prev_mgrp);
1358 			p_prev_mgrp = p_next_mgrp;
1359 		}
1360 	}
1361 
1362 	if (p_next_mgrp)
1363 		sa_db_file_load_handle_mgrp(p_osm, p_prev_mgrp);
1364 
1365 	/*
1366 	 * If loading succeeded, do whatever 'no_clients_rereg' says.
1367 	 * If loading failed at some point, turn off the 'no_clients_rereg'
1368 	 * option (turn on re-registration requests).
1369 	 */
1370 	if (rereg_clients)
1371 		p_osm->subn.opt.no_clients_rereg = FALSE;
1372 
1373 	/* We've just finished loading SA DB file - clear the "dirty" flag */
1374 	p_osm->sa.dirty = FALSE;
1375 
1376 _error:
1377 	fclose(file);
1378 	return ret;
1379 }
1380