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