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 77extern void osm_cpi_rcv_process(IN void *context, IN void *data); 78extern void osm_gir_rcv_process(IN void *context, IN void *data); 79extern void osm_infr_rcv_process(IN void *context, IN void *data); 80extern void osm_infir_rcv_process(IN void *context, IN void *data); 81extern void osm_lftr_rcv_process(IN void *context, IN void *data); 82extern void osm_lr_rcv_process(IN void *context, IN void *data); 83extern void osm_mcmr_rcv_process(IN void *context, IN void *data); 84extern void osm_mftr_rcv_process(IN void *context, IN void *data); 85extern void osm_mpr_rcv_process(IN void *context, IN void *data); 86extern void osm_nr_rcv_process(IN void *context, IN void *data); 87extern void osm_pr_rcv_process(IN void *context, IN void *data); 88extern void osm_pkey_rec_rcv_process(IN void *context, IN void *data); 89extern void osm_pir_rcv_process(IN void *context, IN void *data); 90extern void osm_sr_rcv_process(IN void *context, IN void *data); 91extern void osm_slvl_rec_rcv_process(IN void *context, IN void *data); 92extern void osm_smir_rcv_process(IN void *context, IN void *data); 93extern void osm_sir_rcv_process(IN void *context, IN void *data); 94extern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data); 95extern void osm_sr_rcv_lease_cb(IN void *context); 96 97void 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 106void 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 148void 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 159ib_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; 322Exit: 323 OSM_LOG_EXIT(p_log); 324 return status; 325} 326 327ib_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 342Exit: 343 OSM_LOG_EXIT(p_sa->p_log); 344 return status; 345} 346 347ib_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 363void 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 420Exit: 421 OSM_LOG_EXIT(sa->p_log); 422} 423 424void 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 529Exit: 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 543struct opensm_dump_context { 544 osm_opensm_t *p_osm; 545 FILE *file; 546}; 547 548static int 549opensm_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 610static 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 623static 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 659static 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 703static 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 761static 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 795static 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 818int 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 */ 837static 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 879static 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 916static 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 953static 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) \ 1031static 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 1047UNPACK_FUNC(net, 8); 1048UNPACK_FUNC(net, 16); 1049UNPACK_FUNC(net, 32); 1050UNPACK_FUNC(net, 64); 1051 1052static 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 1067static 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 1093static 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 1108int 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