1/* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5 * 6 * This software is available to you under a choice of one of two 7 * licenses. You may choose to be licensed under the terms of the GNU 8 * General Public License (GPL) Version 2, available from the file 9 * COPYING in the main directory of this source tree, or the 10 * OpenIB.org BSD license below: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * - Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 * 34 */ 35 36/* 37 * Abstract: 38 * Implementation of osm_opensm_t. 39 * This object represents the opensm super object. 40 * This object is part of the opensm family of objects. 41 */ 42 43#if HAVE_CONFIG_H 44# include <config.h> 45#endif /* HAVE_CONFIG_H */ 46 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <complib/cl_dispatcher.h> 51#include <complib/cl_passivelock.h> 52#include <vendor/osm_vendor_api.h> 53#include <opensm/osm_version.h> 54#include <opensm/osm_base.h> 55#include <opensm/osm_opensm.h> 56#include <opensm/osm_log.h> 57#include <opensm/osm_subnet.h> 58#include <opensm/osm_sm.h> 59#include <opensm/osm_vl15intf.h> 60#include <opensm/osm_event_plugin.h> 61 62struct routing_engine_module { 63 const char *name; 64 int (*setup) (struct osm_routing_engine *, osm_opensm_t *); 65}; 66 67extern int osm_ucast_minhop_setup(struct osm_routing_engine *, osm_opensm_t *); 68extern int osm_ucast_updn_setup(struct osm_routing_engine *, osm_opensm_t *); 69extern int osm_ucast_file_setup(struct osm_routing_engine *, osm_opensm_t *); 70extern int osm_ucast_ftree_setup(struct osm_routing_engine *, osm_opensm_t *); 71extern int osm_ucast_lash_setup(struct osm_routing_engine *, osm_opensm_t *); 72extern int osm_ucast_dor_setup(struct osm_routing_engine *, osm_opensm_t *); 73 74const static struct routing_engine_module routing_modules[] = { 75 {"minhop", osm_ucast_minhop_setup}, 76 {"updn", osm_ucast_updn_setup}, 77 {"file", osm_ucast_file_setup}, 78 {"ftree", osm_ucast_ftree_setup}, 79 {"lash", osm_ucast_lash_setup}, 80 {"dor", osm_ucast_dor_setup}, 81 {NULL, NULL} 82}; 83 84/********************************************************************** 85 **********************************************************************/ 86const char *osm_routing_engine_type_str(IN osm_routing_engine_type_t type) 87{ 88 switch (type) { 89 case OSM_ROUTING_ENGINE_TYPE_NONE: 90 return "none"; 91 case OSM_ROUTING_ENGINE_TYPE_MINHOP: 92 return "minhop"; 93 case OSM_ROUTING_ENGINE_TYPE_UPDN: 94 return "updn"; 95 case OSM_ROUTING_ENGINE_TYPE_FILE: 96 return "file"; 97 case OSM_ROUTING_ENGINE_TYPE_FTREE: 98 return "ftree"; 99 case OSM_ROUTING_ENGINE_TYPE_LASH: 100 return "lash"; 101 case OSM_ROUTING_ENGINE_TYPE_DOR: 102 return "dor"; 103 default: 104 break; 105 } 106 return "unknown"; 107} 108 109/********************************************************************** 110 **********************************************************************/ 111osm_routing_engine_type_t osm_routing_engine_type(IN const char *str) 112{ 113 /* For legacy reasons, consider a NULL pointer and the string 114 * "null" as the minhop routing engine. 115 */ 116 if (!str || !strcasecmp(str, "null") 117 || !strcasecmp(str, "minhop")) 118 return OSM_ROUTING_ENGINE_TYPE_MINHOP; 119 else if (!strcasecmp(str, "none")) 120 return OSM_ROUTING_ENGINE_TYPE_NONE; 121 else if (!strcasecmp(str, "updn")) 122 return OSM_ROUTING_ENGINE_TYPE_UPDN; 123 else if (!strcasecmp(str, "file")) 124 return OSM_ROUTING_ENGINE_TYPE_FILE; 125 else if (!strcasecmp(str, "ftree")) 126 return OSM_ROUTING_ENGINE_TYPE_FTREE; 127 else if (!strcasecmp(str, "lash")) 128 return OSM_ROUTING_ENGINE_TYPE_LASH; 129 else if (!strcasecmp(str, "dor")) 130 return OSM_ROUTING_ENGINE_TYPE_DOR; 131 else 132 return OSM_ROUTING_ENGINE_TYPE_UNKNOWN; 133} 134 135/********************************************************************** 136 **********************************************************************/ 137static void append_routing_engine(osm_opensm_t *osm, 138 struct osm_routing_engine *routing_engine) 139{ 140 struct osm_routing_engine *r; 141 142 routing_engine->next = NULL; 143 144 if (!osm->routing_engine_list) { 145 osm->routing_engine_list = routing_engine; 146 return; 147 } 148 149 r = osm->routing_engine_list; 150 while (r->next) 151 r = r->next; 152 153 r->next = routing_engine; 154} 155 156static void setup_routing_engine(osm_opensm_t *osm, const char *name) 157{ 158 struct osm_routing_engine *re; 159 const struct routing_engine_module *m; 160 161 for (m = routing_modules; m->name && *m->name; m++) { 162 if (!strcmp(m->name, name)) { 163 re = malloc(sizeof(struct osm_routing_engine)); 164 if (!re) { 165 OSM_LOG(&osm->log, OSM_LOG_VERBOSE, 166 "memory allocation failed\n"); 167 return; 168 } 169 memset(re, 0, sizeof(struct osm_routing_engine)); 170 171 re->name = m->name; 172 if (m->setup(re, osm)) { 173 OSM_LOG(&osm->log, OSM_LOG_VERBOSE, 174 "setup of routing" 175 " engine \'%s\' failed\n", name); 176 return; 177 } 178 OSM_LOG(&osm->log, OSM_LOG_DEBUG, 179 "\'%s\' routing engine set up\n", re->name); 180 append_routing_engine(osm, re); 181 return; 182 } 183 } 184 185 OSM_LOG(&osm->log, OSM_LOG_ERROR, 186 "cannot find or setup routing engine \'%s\'", name); 187} 188 189static void setup_routing_engines(osm_opensm_t *osm, const char *engine_names) 190{ 191 char *name, *str, *p; 192 193 if (!engine_names || !*engine_names) { 194 setup_routing_engine(osm, "minhop"); 195 return; 196 } 197 198 str = strdup(engine_names); 199 name = strtok_r(str, ", \t\n", &p); 200 while (name && *name) { 201 setup_routing_engine(osm, name); 202 name = strtok_r(NULL, ", \t\n", &p); 203 } 204 free(str); 205 206 if (!osm->routing_engine_list) 207 setup_routing_engine(osm, "minhop"); 208} 209 210/********************************************************************** 211 **********************************************************************/ 212void osm_opensm_construct(IN osm_opensm_t * const p_osm) 213{ 214 memset(p_osm, 0, sizeof(*p_osm)); 215 p_osm->osm_version = OSM_VERSION; 216 osm_subn_construct(&p_osm->subn); 217 osm_sm_construct(&p_osm->sm); 218 osm_sa_construct(&p_osm->sa); 219 osm_db_construct(&p_osm->db); 220 osm_mad_pool_construct(&p_osm->mad_pool); 221 osm_vl15_construct(&p_osm->vl15); 222 osm_log_construct(&p_osm->log); 223} 224 225/********************************************************************** 226 **********************************************************************/ 227static void destroy_routing_engines(osm_opensm_t *osm) 228{ 229 struct osm_routing_engine *r, *next; 230 231 next = osm->routing_engine_list; 232 while (next) { 233 r = next; 234 next = r->next; 235 if (r->delete) 236 r->delete(r->context); 237 free(r); 238 } 239} 240 241/********************************************************************** 242 **********************************************************************/ 243static void destroy_plugins(osm_opensm_t *osm) 244{ 245 osm_epi_plugin_t *p; 246 /* remove from the list, and destroy it */ 247 while (!cl_is_qlist_empty(&osm->plugin_list)){ 248 p = (osm_epi_plugin_t *)cl_qlist_remove_head(&osm->plugin_list); 249 /* plugin is responsible for freeing its own resources */ 250 osm_epi_destroy(p); 251 } 252} 253 254void osm_opensm_destroy(IN osm_opensm_t * const p_osm) 255{ 256 /* in case of shutdown through exit proc - no ^C */ 257 osm_exit_flag = TRUE; 258 259 /* 260 * First of all, clear the is_sm bit. 261 */ 262 if (p_osm->sm.mad_ctrl.h_bind) 263 osm_vendor_set_sm(p_osm->sm.mad_ctrl.h_bind, FALSE); 264 265#ifdef ENABLE_OSM_PERF_MGR 266 /* Shutdown the PerfMgr */ 267 osm_perfmgr_shutdown(&p_osm->perfmgr); 268#endif /* ENABLE_OSM_PERF_MGR */ 269 270 /* shut down the SA 271 * - unbind from QP1 messages 272 */ 273 osm_sa_shutdown(&p_osm->sa); 274 275 /* shut down the SM 276 * - make sure the SM sweeper thread exited 277 * - unbind from QP0 messages 278 */ 279 osm_sm_shutdown(&p_osm->sm); 280 281 /* cleanup all messages on VL15 fifo that were not sent yet */ 282 osm_vl15_shutdown(&p_osm->vl15, &p_osm->mad_pool); 283 284 /* shut down the dispatcher - so no new messages cross */ 285 cl_disp_shutdown(&p_osm->disp); 286 287 /* dump SA DB */ 288 osm_sa_db_file_dump(p_osm); 289 290 /* do the destruction in reverse order as init */ 291 destroy_plugins(p_osm); 292 destroy_routing_engines(p_osm); 293 osm_sa_destroy(&p_osm->sa); 294 osm_sm_destroy(&p_osm->sm); 295#ifdef ENABLE_OSM_PERF_MGR 296 osm_perfmgr_destroy(&p_osm->perfmgr); 297#endif /* ENABLE_OSM_PERF_MGR */ 298 osm_db_destroy(&p_osm->db); 299 osm_vl15_destroy(&p_osm->vl15, &p_osm->mad_pool); 300 osm_mad_pool_destroy(&p_osm->mad_pool); 301 osm_vendor_delete(&p_osm->p_vendor); 302 osm_subn_destroy(&p_osm->subn); 303 cl_disp_destroy(&p_osm->disp); 304#ifdef HAVE_LIBPTHREAD 305 pthread_cond_destroy(&p_osm->stats.cond); 306 pthread_mutex_destroy(&p_osm->stats.mutex); 307#else 308 cl_event_destroy(&p_osm->stats.event); 309#endif 310 close_node_name_map(p_osm->node_name_map); 311 312 cl_plock_destroy(&p_osm->lock); 313 314 osm_log_destroy(&p_osm->log); 315} 316 317static void load_plugins(osm_opensm_t *osm, const char *plugin_names) 318{ 319 osm_epi_plugin_t *epi; 320 char *p_names, *name, *p; 321 322 p_names = strdup(plugin_names); 323 name = strtok_r(p_names, " \t\n", &p); 324 while (name && *name) { 325 epi = osm_epi_construct(osm, name); 326 if (!epi) 327 osm_log(&osm->log, OSM_LOG_ERROR, 328 "cannot load plugin \'%s\'\n", name); 329 else 330 cl_qlist_insert_tail(&osm->plugin_list, &epi->list); 331 name = strtok_r(NULL, " \t\n", &p); 332 } 333 free(p_names); 334} 335 336/********************************************************************** 337 **********************************************************************/ 338ib_api_status_t 339osm_opensm_init(IN osm_opensm_t * const p_osm, 340 IN const osm_subn_opt_t * const p_opt) 341{ 342 ib_api_status_t status; 343 344 /* Can't use log macros here, since we're initializing the log */ 345 osm_opensm_construct(p_osm); 346 347 if (p_opt->daemon) 348 p_osm->log.daemon = 1; 349 350 status = osm_log_init_v2(&p_osm->log, p_opt->force_log_flush, 351 p_opt->log_flags, p_opt->log_file, 352 p_opt->log_max_size, p_opt->accum_log_file); 353 if (status != IB_SUCCESS) 354 return (status); 355 356 /* If there is a log level defined - add the OSM_VERSION to it */ 357 osm_log(&p_osm->log, 358 osm_log_get_level(&p_osm->log) & (OSM_LOG_SYS ^ 0xFF), "%s\n", 359 p_osm->osm_version); 360 /* Write the OSM_VERSION to the SYS_LOG */ 361 osm_log(&p_osm->log, OSM_LOG_SYS, "%s\n", p_osm->osm_version); /* Format Waived */ 362 363 OSM_LOG(&p_osm->log, OSM_LOG_FUNCS, "[\n"); /* Format Waived */ 364 365 status = cl_plock_init(&p_osm->lock); 366 if (status != IB_SUCCESS) 367 goto Exit; 368 369#ifdef HAVE_LIBPTHREAD 370 pthread_mutex_init(&p_osm->stats.mutex, NULL); 371 pthread_cond_init(&p_osm->stats.cond, NULL); 372#else 373 status = cl_event_init(&p_osm->stats.event, FALSE); 374 if (status != IB_SUCCESS) 375 goto Exit; 376#endif 377 378 if (p_opt->single_thread) { 379 OSM_LOG(&p_osm->log, OSM_LOG_INFO, 380 "Forcing single threaded dispatcher\n"); 381 status = cl_disp_init(&p_osm->disp, 1, "opensm"); 382 } else { 383 /* 384 * Normal behavior is to initialize the dispatcher with 385 * one thread per CPU, as specified by a thread count of '0'. 386 */ 387 status = cl_disp_init(&p_osm->disp, 0, "opensm"); 388 } 389 if (status != IB_SUCCESS) 390 goto Exit; 391 392 status = osm_subn_init(&p_osm->subn, p_osm, p_opt); 393 if (status != IB_SUCCESS) 394 goto Exit; 395 396 p_osm->p_vendor = 397 osm_vendor_new(&p_osm->log, p_opt->transaction_timeout); 398 if (p_osm->p_vendor == NULL) { 399 status = IB_INSUFFICIENT_RESOURCES; 400 goto Exit; 401 } 402 403 status = osm_mad_pool_init(&p_osm->mad_pool); 404 if (status != IB_SUCCESS) 405 goto Exit; 406 407 status = osm_vl15_init(&p_osm->vl15, p_osm->p_vendor, 408 &p_osm->log, &p_osm->stats, 409 p_opt->max_wire_smps); 410 if (status != IB_SUCCESS) 411 goto Exit; 412 413 /* the DB is in use by the SM and SA so init before */ 414 status = osm_db_init(&p_osm->db, &p_osm->log); 415 if (status != IB_SUCCESS) 416 goto Exit; 417 418 status = osm_sm_init(&p_osm->sm, &p_osm->subn, &p_osm->db, 419 p_osm->p_vendor, &p_osm->mad_pool, &p_osm->vl15, 420 &p_osm->log, &p_osm->stats, &p_osm->disp, 421 &p_osm->lock); 422 423 if (status != IB_SUCCESS) 424 goto Exit; 425 426 status = osm_sa_init(&p_osm->sm, &p_osm->sa, &p_osm->subn, 427 p_osm->p_vendor, &p_osm->mad_pool, &p_osm->log, 428 &p_osm->stats, &p_osm->disp, &p_osm->lock); 429 430 if (status != IB_SUCCESS) 431 goto Exit; 432 433 cl_qlist_init(&p_osm->plugin_list); 434 435 if (p_opt->event_plugin_name) 436 load_plugins(p_osm, p_opt->event_plugin_name); 437 438#ifdef ENABLE_OSM_PERF_MGR 439 status = osm_perfmgr_init(&p_osm->perfmgr, p_osm, p_opt); 440 if (status != IB_SUCCESS) 441 goto Exit; 442#endif /* ENABLE_OSM_PERF_MGR */ 443 444 setup_routing_engines(p_osm, p_opt->routing_engine_names); 445 446 p_osm->routing_engine_used = OSM_ROUTING_ENGINE_TYPE_NONE; 447 448 p_osm->node_name_map = open_node_name_map(p_opt->node_name_map_name); 449 450Exit: 451 OSM_LOG(&p_osm->log, OSM_LOG_FUNCS, "]\n"); /* Format Waived */ 452 return (status); 453} 454 455/********************************************************************** 456 **********************************************************************/ 457ib_api_status_t 458osm_opensm_bind(IN osm_opensm_t * const p_osm, IN const ib_net64_t guid) 459{ 460 ib_api_status_t status; 461 462 OSM_LOG_ENTER(&p_osm->log); 463 464 status = osm_sm_bind(&p_osm->sm, guid); 465 if (status != IB_SUCCESS) 466 goto Exit; 467 468 status = osm_sa_bind(&p_osm->sa, guid); 469 if (status != IB_SUCCESS) 470 goto Exit; 471 472#ifdef ENABLE_OSM_PERF_MGR 473 status = osm_perfmgr_bind(&p_osm->perfmgr, guid); 474 if (status != IB_SUCCESS) 475 goto Exit; 476#endif /* ENABLE_OSM_PERF_MGR */ 477 478Exit: 479 OSM_LOG_EXIT(&p_osm->log); 480 return (status); 481} 482 483/********************************************************************** 484 **********************************************************************/ 485void osm_opensm_report_event(osm_opensm_t *osm, osm_epi_event_id_t event_id, 486 void *event_data) 487{ 488 cl_list_item_t *item; 489 490 for (item = cl_qlist_head(&osm->plugin_list); 491 item != cl_qlist_end(&osm->plugin_list); 492 item = cl_qlist_next(item)) { 493 osm_epi_plugin_t *p = (osm_epi_plugin_t *)item; 494 if (p->impl->report) 495 p->impl->report(p->plugin_data, event_id, event_data); 496 } 497} 498