]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_opensm.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_opensm.c
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
62 struct routing_engine_module {
63         const char *name;
64         int (*setup) (struct osm_routing_engine *, osm_opensm_t *);
65 };
66
67 extern int osm_ucast_minhop_setup(struct osm_routing_engine *, osm_opensm_t *);
68 extern int osm_ucast_updn_setup(struct osm_routing_engine *, osm_opensm_t *);
69 extern int osm_ucast_file_setup(struct osm_routing_engine *, osm_opensm_t *);
70 extern int osm_ucast_ftree_setup(struct osm_routing_engine *, osm_opensm_t *);
71 extern int osm_ucast_lash_setup(struct osm_routing_engine *, osm_opensm_t *);
72 extern int osm_ucast_dor_setup(struct osm_routing_engine *, osm_opensm_t *);
73
74 const 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  **********************************************************************/
86 const 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  **********************************************************************/
111 osm_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  **********************************************************************/
137 static 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
156 static 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
189 static 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  **********************************************************************/
212 void 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  **********************************************************************/
227 static 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  **********************************************************************/
243 static 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
254 void 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
317 static 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  **********************************************************************/
338 ib_api_status_t
339 osm_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
450 Exit:
451         OSM_LOG(&p_osm->log, OSM_LOG_FUNCS, "]\n");     /* Format Waived */
452         return (status);
453 }
454
455 /**********************************************************************
456  **********************************************************************/
457 ib_api_status_t
458 osm_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
478 Exit:
479         OSM_LOG_EXIT(&p_osm->log);
480         return (status);
481 }
482
483 /**********************************************************************
484  **********************************************************************/
485 void 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 }