1/*
2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2008 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_subn_t.
40 * This object represents an IBA subnet.
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 <stdio.h>
50#include <stdarg.h>
51#include <limits.h>
52#include <errno.h>
53#include <ctype.h>
54#include <complib/cl_debug.h>
55#include <complib/cl_log.h>
56#include <opensm/osm_subnet.h>
57#include <opensm/osm_opensm.h>
58#include <opensm/osm_log.h>
59#include <opensm/osm_madw.h>
60#include <opensm/osm_port.h>
61#include <opensm/osm_switch.h>
62#include <opensm/osm_remote_sm.h>
63#include <opensm/osm_partition.h>
64#include <opensm/osm_node.h>
65#include <opensm/osm_multicast.h>
66#include <opensm/osm_inform.h>
67#include <opensm/osm_console.h>
68#include <opensm/osm_perfmgr.h>
69#include <opensm/osm_event_plugin.h>
70#include <opensm/osm_qos_policy.h>
71
72static const char null_str[] = "(null)";
73
74/**********************************************************************
75 **********************************************************************/
76void osm_subn_construct(IN osm_subn_t * const p_subn)
77{
78	memset(p_subn, 0, sizeof(*p_subn));
79	cl_ptr_vector_construct(&p_subn->port_lid_tbl);
80	cl_qmap_init(&p_subn->sw_guid_tbl);
81	cl_qmap_init(&p_subn->node_guid_tbl);
82	cl_qmap_init(&p_subn->port_guid_tbl);
83	cl_qmap_init(&p_subn->sm_guid_tbl);
84	cl_qlist_init(&p_subn->sa_sr_list);
85	cl_qlist_init(&p_subn->sa_infr_list);
86	cl_qlist_init(&p_subn->prefix_routes_list);
87	cl_qmap_init(&p_subn->rtr_guid_tbl);
88	cl_qmap_init(&p_subn->prtn_pkey_tbl);
89}
90
91/**********************************************************************
92 **********************************************************************/
93void osm_subn_destroy(IN osm_subn_t * const p_subn)
94{
95	int i;
96	osm_node_t *p_node, *p_next_node;
97	osm_port_t *p_port, *p_next_port;
98	osm_switch_t *p_sw, *p_next_sw;
99	osm_remote_sm_t *p_rsm, *p_next_rsm;
100	osm_prtn_t *p_prtn, *p_next_prtn;
101	osm_mgrp_t *p_mgrp;
102	osm_infr_t *p_infr, *p_next_infr;
103
104	/* it might be a good idea to de-allocate all known objects */
105	p_next_node = (osm_node_t *) cl_qmap_head(&p_subn->node_guid_tbl);
106	while (p_next_node !=
107	       (osm_node_t *) cl_qmap_end(&p_subn->node_guid_tbl)) {
108		p_node = p_next_node;
109		p_next_node = (osm_node_t *) cl_qmap_next(&p_node->map_item);
110		osm_node_delete(&p_node);
111	}
112
113	p_next_port = (osm_port_t *) cl_qmap_head(&p_subn->port_guid_tbl);
114	while (p_next_port !=
115	       (osm_port_t *) cl_qmap_end(&p_subn->port_guid_tbl)) {
116		p_port = p_next_port;
117		p_next_port = (osm_port_t *) cl_qmap_next(&p_port->map_item);
118		osm_port_delete(&p_port);
119	}
120
121	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
122	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
123		p_sw = p_next_sw;
124		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
125		osm_switch_delete(&p_sw);
126	}
127
128	p_next_rsm = (osm_remote_sm_t *) cl_qmap_head(&p_subn->sm_guid_tbl);
129	while (p_next_rsm !=
130	       (osm_remote_sm_t *) cl_qmap_end(&p_subn->sm_guid_tbl)) {
131		p_rsm = p_next_rsm;
132		p_next_rsm = (osm_remote_sm_t *) cl_qmap_next(&p_rsm->map_item);
133		free(p_rsm);
134	}
135
136	p_next_prtn = (osm_prtn_t *) cl_qmap_head(&p_subn->prtn_pkey_tbl);
137	while (p_next_prtn !=
138	       (osm_prtn_t *) cl_qmap_end(&p_subn->prtn_pkey_tbl)) {
139		p_prtn = p_next_prtn;
140		p_next_prtn = (osm_prtn_t *) cl_qmap_next(&p_prtn->map_item);
141		osm_prtn_delete(&p_prtn);
142	}
143
144	for (i = 0; i <= p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO;
145	     i++) {
146		p_mgrp = p_subn->mgroups[i];
147		p_subn->mgroups[i] = NULL;
148		if (p_mgrp)
149			osm_mgrp_delete(p_mgrp);
150	}
151
152	p_next_infr = (osm_infr_t *) cl_qlist_head(&p_subn->sa_infr_list);
153	while (p_next_infr !=
154	       (osm_infr_t *) cl_qlist_end(&p_subn->sa_infr_list)) {
155		p_infr = p_next_infr;
156		p_next_infr = (osm_infr_t *) cl_qlist_next(&p_infr->list_item);
157		osm_infr_delete(p_infr);
158	}
159
160	cl_ptr_vector_destroy(&p_subn->port_lid_tbl);
161
162	osm_qos_policy_destroy(p_subn->p_qos_policy);
163
164	while (!cl_is_qlist_empty(&p_subn->prefix_routes_list)) {
165		cl_list_item_t *item = cl_qlist_remove_head(&p_subn->prefix_routes_list);
166		free(item);
167	}
168}
169
170/**********************************************************************
171 **********************************************************************/
172ib_api_status_t
173osm_subn_init(IN osm_subn_t * const p_subn,
174	      IN osm_opensm_t * const p_osm,
175	      IN const osm_subn_opt_t * const p_opt)
176{
177	cl_status_t status;
178
179	p_subn->p_osm = p_osm;
180
181	status = cl_ptr_vector_init(&p_subn->port_lid_tbl,
182				    OSM_SUBNET_VECTOR_MIN_SIZE,
183				    OSM_SUBNET_VECTOR_GROW_SIZE);
184	if (status != CL_SUCCESS)
185		return (status);
186
187	status = cl_ptr_vector_set_capacity(&p_subn->port_lid_tbl,
188					    OSM_SUBNET_VECTOR_CAPACITY);
189	if (status != CL_SUCCESS)
190		return (status);
191
192	/*
193	   LID zero is not valid.  NULL out this entry for the
194	   convenience of other code.
195	 */
196	cl_ptr_vector_set(&p_subn->port_lid_tbl, 0, NULL);
197
198	p_subn->opt = *p_opt;
199	p_subn->max_ucast_lid_ho = IB_LID_UCAST_END_HO;
200	p_subn->max_mcast_lid_ho = IB_LID_MCAST_END_HO;
201	p_subn->min_ca_mtu = IB_MAX_MTU;
202	p_subn->min_ca_rate = IB_MAX_RATE;
203	p_subn->ignore_existing_lfts = TRUE;
204
205	/* we assume master by default - so we only need to set it true if STANDBY */
206	p_subn->coming_out_of_standby = FALSE;
207
208	return (IB_SUCCESS);
209}
210
211/**********************************************************************
212 **********************************************************************/
213ib_api_status_t
214osm_get_gid_by_mad_addr(IN osm_log_t * p_log,
215			IN const osm_subn_t * p_subn,
216			IN const osm_mad_addr_t * p_mad_addr,
217			OUT ib_gid_t * p_gid)
218{
219	const cl_ptr_vector_t *p_tbl;
220	const osm_port_t *p_port = NULL;
221
222	if (p_gid == NULL) {
223		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7505: "
224			"Provided output GID is NULL\n");
225		return (IB_INVALID_PARAMETER);
226	}
227
228	/* Find the port gid of the request in the subnet */
229	p_tbl = &p_subn->port_lid_tbl;
230
231	CL_ASSERT(cl_ptr_vector_get_size(p_tbl) < 0x10000);
232
233	if ((uint16_t) cl_ptr_vector_get_size(p_tbl) >
234	    cl_ntoh16(p_mad_addr->dest_lid)) {
235		p_port =
236		    cl_ptr_vector_get(p_tbl, cl_ntoh16(p_mad_addr->dest_lid));
237		if (p_port == NULL) {
238			OSM_LOG(p_log, OSM_LOG_DEBUG,
239				"Did not find any port with LID: %u\n",
240				cl_ntoh16(p_mad_addr->dest_lid));
241			return (IB_INVALID_PARAMETER);
242		}
243		p_gid->unicast.interface_id = p_port->p_physp->port_guid;
244		p_gid->unicast.prefix = p_subn->opt.subnet_prefix;
245	} else {
246		/* The dest_lid is not in the subnet table - this is an error */
247		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7501: "
248			"LID is out of range: %u\n",
249			cl_ntoh16(p_mad_addr->dest_lid));
250		return (IB_INVALID_PARAMETER);
251	}
252
253	return (IB_SUCCESS);
254}
255
256/**********************************************************************
257 **********************************************************************/
258osm_physp_t *osm_get_physp_by_mad_addr(IN osm_log_t * p_log,
259				       IN const osm_subn_t * p_subn,
260				       IN osm_mad_addr_t * p_mad_addr)
261{
262	const cl_ptr_vector_t *p_port_lid_tbl;
263	osm_port_t *p_port = NULL;
264	osm_physp_t *p_physp = NULL;
265
266	/* Find the port gid of the request in the subnet */
267	p_port_lid_tbl = &p_subn->port_lid_tbl;
268
269	CL_ASSERT(cl_ptr_vector_get_size(p_port_lid_tbl) < 0x10000);
270
271	if ((uint16_t) cl_ptr_vector_get_size(p_port_lid_tbl) >
272	    cl_ntoh16(p_mad_addr->dest_lid)) {
273		p_port =
274		    cl_ptr_vector_get(p_port_lid_tbl,
275				      cl_ntoh16(p_mad_addr->dest_lid));
276		if (p_port == NULL) {
277			/* The port is not in the port_lid table - this is an error */
278			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7502: "
279				"Cannot locate port object by lid: %u\n",
280				cl_ntoh16(p_mad_addr->dest_lid));
281
282			goto Exit;
283		}
284		p_physp = p_port->p_physp;
285	} else {
286		/* The dest_lid is not in the subnet table - this is an error */
287		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7503: "
288			"Lid is out of range: %u\n",
289			cl_ntoh16(p_mad_addr->dest_lid));
290	}
291
292Exit:
293	return p_physp;
294}
295
296/**********************************************************************
297 **********************************************************************/
298osm_port_t *osm_get_port_by_mad_addr(IN osm_log_t * p_log,
299				     IN const osm_subn_t * p_subn,
300				     IN osm_mad_addr_t * p_mad_addr)
301{
302	const cl_ptr_vector_t *p_port_lid_tbl;
303	osm_port_t *p_port = NULL;
304
305	/* Find the port gid of the request in the subnet */
306	p_port_lid_tbl = &p_subn->port_lid_tbl;
307
308	CL_ASSERT(cl_ptr_vector_get_size(p_port_lid_tbl) < 0x10000);
309
310	if ((uint16_t) cl_ptr_vector_get_size(p_port_lid_tbl) >
311	    cl_ntoh16(p_mad_addr->dest_lid)) {
312		p_port =
313		    cl_ptr_vector_get(p_port_lid_tbl,
314				      cl_ntoh16(p_mad_addr->dest_lid));
315	} else {
316		/* The dest_lid is not in the subnet table - this is an error */
317		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7504: "
318			"Lid is out of range: %u\n",
319			cl_ntoh16(p_mad_addr->dest_lid));
320	}
321
322	return p_port;
323}
324
325/**********************************************************************
326 **********************************************************************/
327osm_switch_t *osm_get_switch_by_guid(IN const osm_subn_t * p_subn,
328				     IN uint64_t guid)
329{
330	osm_switch_t *p_switch;
331
332	p_switch = (osm_switch_t *) cl_qmap_get(&(p_subn->sw_guid_tbl), guid);
333	if (p_switch == (osm_switch_t *) cl_qmap_end(&(p_subn->sw_guid_tbl)))
334		p_switch = NULL;
335	return p_switch;
336}
337
338/**********************************************************************
339 **********************************************************************/
340osm_node_t *osm_get_node_by_guid(IN osm_subn_t const *p_subn, IN uint64_t guid)
341{
342	osm_node_t *p_node;
343
344	p_node = (osm_node_t *) cl_qmap_get(&(p_subn->node_guid_tbl), guid);
345	if (p_node == (osm_node_t *) cl_qmap_end(&(p_subn->node_guid_tbl)))
346		p_node = NULL;
347	return p_node;
348}
349
350/**********************************************************************
351 **********************************************************************/
352osm_port_t *osm_get_port_by_guid(IN osm_subn_t const *p_subn, IN ib_net64_t guid)
353{
354	osm_port_t *p_port;
355
356	p_port = (osm_port_t *) cl_qmap_get(&(p_subn->port_guid_tbl), guid);
357	if (p_port == (osm_port_t *) cl_qmap_end(&(p_subn->port_guid_tbl)))
358		p_port = NULL;
359	return p_port;
360}
361
362/**********************************************************************
363 **********************************************************************/
364static void subn_set_default_qos_options(IN osm_qos_options_t * opt)
365{
366	opt->max_vls = OSM_DEFAULT_QOS_MAX_VLS;
367	opt->high_limit = OSM_DEFAULT_QOS_HIGH_LIMIT;
368	opt->vlarb_high = OSM_DEFAULT_QOS_VLARB_HIGH;
369	opt->vlarb_low = OSM_DEFAULT_QOS_VLARB_LOW;
370	opt->sl2vl = OSM_DEFAULT_QOS_SL2VL;
371}
372
373static void subn_init_qos_options(IN osm_qos_options_t * opt)
374{
375	opt->max_vls = 0;
376	opt->high_limit = -1;
377	opt->vlarb_high = NULL;
378	opt->vlarb_low = NULL;
379	opt->sl2vl = NULL;
380}
381
382/**********************************************************************
383 **********************************************************************/
384void osm_subn_set_default_opt(IN osm_subn_opt_t * const p_opt)
385{
386	memset(p_opt, 0, sizeof(osm_subn_opt_t));
387	p_opt->guid = 0;
388	p_opt->m_key = OSM_DEFAULT_M_KEY;
389	p_opt->sm_key = OSM_DEFAULT_SM_KEY;
390	p_opt->sa_key = OSM_DEFAULT_SA_KEY;
391	p_opt->subnet_prefix = IB_DEFAULT_SUBNET_PREFIX;
392	p_opt->m_key_lease_period = 0;
393	p_opt->sweep_interval = OSM_DEFAULT_SWEEP_INTERVAL_SECS;
394	p_opt->max_wire_smps = OSM_DEFAULT_SMP_MAX_ON_WIRE;
395	p_opt->console = OSM_DEFAULT_CONSOLE;
396	p_opt->console_port = OSM_DEFAULT_CONSOLE_PORT;
397	p_opt->transaction_timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC;
398	/* by default we will consider waiting for 50x transaction timeout normal */
399	p_opt->max_msg_fifo_timeout = 50 * OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC;
400	p_opt->sm_priority = OSM_DEFAULT_SM_PRIORITY;
401	p_opt->lmc = OSM_DEFAULT_LMC;
402	p_opt->lmc_esp0 = FALSE;
403	p_opt->max_op_vls = OSM_DEFAULT_MAX_OP_VLS;
404	p_opt->force_link_speed = 15;
405	p_opt->reassign_lids = FALSE;
406	p_opt->ignore_other_sm = FALSE;
407	p_opt->single_thread = FALSE;
408	p_opt->disable_multicast = FALSE;
409	p_opt->force_log_flush = FALSE;
410	p_opt->subnet_timeout = OSM_DEFAULT_SUBNET_TIMEOUT;
411	p_opt->packet_life_time = OSM_DEFAULT_SWITCH_PACKET_LIFE;
412	p_opt->vl_stall_count = OSM_DEFAULT_VL_STALL_COUNT;
413	p_opt->leaf_vl_stall_count = OSM_DEFAULT_LEAF_VL_STALL_COUNT;
414	p_opt->head_of_queue_lifetime = OSM_DEFAULT_HEAD_OF_QUEUE_LIFE;
415	p_opt->leaf_head_of_queue_lifetime =
416	    OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE;
417	p_opt->local_phy_errors_threshold = OSM_DEFAULT_ERROR_THRESHOLD;
418	p_opt->overrun_errors_threshold = OSM_DEFAULT_ERROR_THRESHOLD;
419	p_opt->sminfo_polling_timeout =
420	    OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS;
421	p_opt->polling_retry_number = OSM_SM_DEFAULT_POLLING_RETRY_NUMBER;
422	p_opt->force_heavy_sweep = FALSE;
423	p_opt->log_flags = OSM_LOG_DEFAULT_LEVEL;
424	p_opt->honor_guid2lid_file = FALSE;
425	p_opt->daemon = FALSE;
426	p_opt->sm_inactive = FALSE;
427	p_opt->babbling_port_policy = FALSE;
428#ifdef ENABLE_OSM_PERF_MGR
429	p_opt->perfmgr = FALSE;
430	p_opt->perfmgr_redir = TRUE;
431	p_opt->perfmgr_sweep_time_s = OSM_PERFMGR_DEFAULT_SWEEP_TIME_S;
432	p_opt->perfmgr_max_outstanding_queries =
433	    OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES;
434	p_opt->event_db_dump_file = NULL; /* use default */
435#endif				/* ENABLE_OSM_PERF_MGR */
436
437	p_opt->event_plugin_name = NULL;
438	p_opt->node_name_map_name = NULL;
439
440	p_opt->dump_files_dir = getenv("OSM_TMP_DIR");
441	if (!p_opt->dump_files_dir || !(*p_opt->dump_files_dir))
442		p_opt->dump_files_dir = OSM_DEFAULT_TMP_DIR;
443
444	p_opt->log_file = OSM_DEFAULT_LOG_FILE;
445	p_opt->log_max_size = 0;
446	p_opt->partition_config_file = OSM_DEFAULT_PARTITION_CONFIG_FILE;
447	p_opt->no_partition_enforcement = FALSE;
448	p_opt->qos = FALSE;
449	p_opt->qos_policy_file = OSM_DEFAULT_QOS_POLICY_FILE;
450	p_opt->accum_log_file = TRUE;
451	p_opt->port_prof_ignore_file = NULL;
452	p_opt->port_profile_switch_nodes = FALSE;
453	p_opt->sweep_on_trap = TRUE;
454	p_opt->use_ucast_cache = FALSE;
455	p_opt->routing_engine_names = NULL;
456	p_opt->connect_roots = FALSE;
457	p_opt->lid_matrix_dump_file = NULL;
458	p_opt->lfts_file = NULL;
459	p_opt->root_guid_file = NULL;
460	p_opt->cn_guid_file = NULL;
461	p_opt->ids_guid_file = NULL;
462	p_opt->guid_routing_order_file = NULL;
463	p_opt->sa_db_file = NULL;
464	p_opt->exit_on_fatal = TRUE;
465	p_opt->enable_quirks = FALSE;
466	p_opt->no_clients_rereg = FALSE;
467	p_opt->prefix_routes_file = OSM_DEFAULT_PREFIX_ROUTES_FILE;
468	p_opt->consolidate_ipv6_snm_req = FALSE;
469	subn_init_qos_options(&p_opt->qos_options);
470	subn_init_qos_options(&p_opt->qos_ca_options);
471	subn_init_qos_options(&p_opt->qos_sw0_options);
472	subn_init_qos_options(&p_opt->qos_swe_options);
473	subn_init_qos_options(&p_opt->qos_rtr_options);
474}
475
476/**********************************************************************
477 **********************************************************************/
478static void log_report(const char *fmt, ...)
479{
480	char buf[128];
481	va_list args;
482	va_start(args, fmt);
483	vsnprintf(buf, sizeof(buf), fmt, args);
484	va_end(args);
485	printf("%s", buf);
486	cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0);
487}
488
489static void log_config_value(char *name, const char *fmt, ...)
490{
491	char buf[128];
492	va_list args;
493	unsigned n;
494	va_start(args, fmt);
495	n = snprintf(buf, sizeof(buf), " Loading Cached Option:%s = ", name);
496	if (n > sizeof(buf))
497		n = sizeof(buf);
498	n += vsnprintf(buf + n, sizeof(buf) - n, fmt, args);
499	if (n > sizeof(buf))
500		n = sizeof(buf);
501	snprintf(buf + n, sizeof(buf) - n, "\n");
502	va_end(args);
503	printf("%s", buf);
504	cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0);
505}
506
507static void
508opts_unpack_net64(IN char *p_req_key,
509		  IN char *p_key, IN char *p_val_str, IN uint64_t * p_val)
510{
511	if (!strcmp(p_req_key, p_key)) {
512		uint64_t val = strtoull(p_val_str, NULL, 0);
513		if (cl_hton64(val) != *p_val) {
514			log_config_value(p_key, "0x%016" PRIx64, val);
515			*p_val = cl_ntoh64(val);
516		}
517	}
518}
519
520/**********************************************************************
521 **********************************************************************/
522static void
523opts_unpack_uint32(IN char *p_req_key,
524		   IN char *p_key, IN char *p_val_str, IN uint32_t * p_val)
525{
526	if (!strcmp(p_req_key, p_key)) {
527		uint32_t val = strtoul(p_val_str, NULL, 0);
528		if (val != *p_val) {
529			log_config_value(p_key, "%u", val);
530			*p_val = val;
531		}
532	}
533}
534
535/**********************************************************************
536 **********************************************************************/
537static void
538opts_unpack_int32(IN char *p_req_key,
539		  IN char *p_key, IN char *p_val_str, IN int32_t * p_val)
540{
541	if (!strcmp(p_req_key, p_key)) {
542		int32_t val = strtol(p_val_str, NULL, 0);
543		if (val != *p_val) {
544			log_config_value(p_key, "%d", val);
545			*p_val = val;
546		}
547	}
548}
549
550/**********************************************************************
551 **********************************************************************/
552static void
553opts_unpack_uint16(IN char *p_req_key,
554		   IN char *p_key, IN char *p_val_str, IN uint16_t * p_val)
555{
556	if (!strcmp(p_req_key, p_key)) {
557		uint16_t val = (uint16_t) strtoul(p_val_str, NULL, 0);
558		if (val != *p_val) {
559			log_config_value(p_key, "%u", val);
560			*p_val = val;
561		}
562	}
563}
564
565/**********************************************************************
566 **********************************************************************/
567static void
568opts_unpack_net16(IN char *p_req_key,
569		  IN char *p_key, IN char *p_val_str, IN uint16_t * p_val)
570{
571	if (!strcmp(p_req_key, p_key)) {
572		uint32_t val;
573		val = strtoul(p_val_str, NULL, 0);
574		CL_ASSERT(val < 0x10000);
575		if (cl_hton32(val) != *p_val) {
576			log_config_value(p_key, "0x%04x", val);
577			*p_val = cl_hton16((uint16_t) val);
578		}
579	}
580}
581
582/**********************************************************************
583 **********************************************************************/
584static void
585opts_unpack_uint8(IN char *p_req_key,
586		  IN char *p_key, IN char *p_val_str, IN uint8_t * p_val)
587{
588	if (!strcmp(p_req_key, p_key)) {
589		uint32_t val;
590		val = strtoul(p_val_str, NULL, 0);
591		CL_ASSERT(val < 0x100);
592		if (val != *p_val) {
593			log_config_value(p_key, "%u", val);
594			*p_val = (uint8_t) val;
595		}
596	}
597}
598
599/**********************************************************************
600 **********************************************************************/
601static void
602opts_unpack_boolean(IN char *p_req_key,
603		    IN char *p_key, IN char *p_val_str, IN boolean_t * p_val)
604{
605	if (!strcmp(p_req_key, p_key) && p_val_str) {
606		boolean_t val;
607		if (strcmp("TRUE", p_val_str))
608			val = FALSE;
609		else
610			val = TRUE;
611
612		if (val != *p_val) {
613			log_config_value(p_key, "%s", p_val_str);
614			*p_val = val;
615		}
616	}
617}
618
619/**********************************************************************
620 **********************************************************************/
621static void
622opts_unpack_charp(IN char *p_req_key,
623		  IN char *p_key, IN char *p_val_str, IN char **p_val)
624{
625	if (!strcmp(p_req_key, p_key) && p_val_str) {
626		const char *current_str = *p_val ? *p_val : null_str ;
627		if (strcmp(p_val_str, current_str)) {
628			log_config_value(p_key, "%s", p_val_str);
629			/* special case the "(null)" string */
630			if (strcmp(null_str, p_val_str) == 0) {
631				*p_val = NULL;
632			} else {
633				/*
634				  Ignore the possible memory leak here;
635				  the pointer may be to a static default.
636				*/
637				*p_val = strdup(p_val_str);
638			}
639		}
640	}
641}
642
643/**********************************************************************
644 **********************************************************************/
645static char *clean_val(char *val)
646{
647	char *p = val;
648	/* clean leading spaces */
649	while (isspace(*p))
650		p++;
651	val = p;
652	if (!*val)
653		return val;
654	/* clean trailing spaces */
655	p = val + strlen(val) - 1;
656	while (p > val && isspace(*p))
657		p--;
658	p[1] = '\0';
659	/* clean quotas */
660	if ((*val == '\"' && *p == '\"') || (*val == '\'' && *p == '\'')) {
661		val++;
662		p--;
663	}
664	return val;
665}
666
667/**********************************************************************
668 **********************************************************************/
669static void
670subn_parse_qos_options(IN const char *prefix,
671		       IN char *p_key,
672		       IN char *p_val_str, IN osm_qos_options_t * opt)
673{
674	char name[256];
675
676	snprintf(name, sizeof(name), "%s_max_vls", prefix);
677	opts_unpack_uint32(name, p_key, p_val_str, &opt->max_vls);
678	snprintf(name, sizeof(name), "%s_high_limit", prefix);
679	opts_unpack_int32(name, p_key, p_val_str, &opt->high_limit);
680	snprintf(name, sizeof(name), "%s_vlarb_high", prefix);
681	opts_unpack_charp(name, p_key, p_val_str, &opt->vlarb_high);
682	snprintf(name, sizeof(name), "%s_vlarb_low", prefix);
683	opts_unpack_charp(name, p_key, p_val_str, &opt->vlarb_low);
684	snprintf(name, sizeof(name), "%s_sl2vl", prefix);
685	opts_unpack_charp(name, p_key, p_val_str, &opt->sl2vl);
686}
687
688static int
689subn_dump_qos_options(FILE * file,
690		      const char *set_name,
691		      const char *prefix, osm_qos_options_t * opt)
692{
693	return fprintf(file, "# %s\n"
694		       "%s_max_vls %u\n"
695		       "%s_high_limit %d\n"
696		       "%s_vlarb_high %s\n"
697		       "%s_vlarb_low %s\n"
698		       "%s_sl2vl %s\n",
699		       set_name,
700		       prefix, opt->max_vls,
701		       prefix, opt->high_limit,
702		       prefix, opt->vlarb_high,
703		       prefix, opt->vlarb_low, prefix, opt->sl2vl);
704}
705
706/**********************************************************************
707 **********************************************************************/
708static ib_api_status_t
709append_prefix_route(IN osm_subn_t * const p_subn, uint64_t prefix, uint64_t guid)
710{
711	osm_prefix_route_t *route;
712
713	route = malloc(sizeof *route);
714	if (! route) {
715		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "out of memory");
716		return IB_ERROR;
717	}
718
719	route->prefix = cl_hton64(prefix);
720	route->guid = cl_hton64(guid);
721	cl_qlist_insert_tail(&p_subn->prefix_routes_list, &route->list_item);
722	return IB_SUCCESS;
723}
724
725static ib_api_status_t
726osm_parse_prefix_routes_file(IN osm_subn_t * const p_subn)
727{
728	osm_log_t *log = &p_subn->p_osm->log;
729	FILE *fp;
730	char buf[1024];
731	int line = 0;
732	int errors = 0;
733
734	while (!cl_is_qlist_empty(&p_subn->prefix_routes_list)) {
735		cl_list_item_t *item = cl_qlist_remove_head(&p_subn->prefix_routes_list);
736		free(item);
737	}
738
739	fp = fopen(p_subn->opt.prefix_routes_file, "r");
740	if (! fp) {
741		if (errno == ENOENT)
742			return IB_SUCCESS;
743
744		OSM_LOG(log, OSM_LOG_ERROR, "fopen(%s) failed: %s",
745			p_subn->opt.prefix_routes_file, strerror(errno));
746		return IB_ERROR;
747	}
748
749	while (fgets(buf, sizeof buf, fp) != NULL) {
750		char *p_prefix, *p_guid, *p_extra, *p_last, *p_end;
751		uint64_t prefix, guid;
752
753		line++;
754		if (errors > 10)
755			break;
756
757		p_prefix = strtok_r(buf, " \t\n", &p_last);
758		if (! p_prefix)
759			continue; /* ignore blank lines */
760
761		if (*p_prefix == '#')
762			continue; /* ignore comment lines */
763
764		p_guid = strtok_r(NULL, " \t\n", &p_last);
765		if (! p_guid) {
766			OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: missing GUID\n",
767				p_subn->opt.prefix_routes_file, line);
768			errors++;
769			continue;
770		}
771
772		p_extra = strtok_r(NULL, " \t\n", &p_last);
773		if (p_extra && *p_extra != '#') {
774			OSM_LOG(log, OSM_LOG_INFO, "%s:%d: extra tokens ignored\n",
775				p_subn->opt.prefix_routes_file, line);
776		}
777
778		if (strcmp(p_prefix, "*") == 0)
779			prefix = 0;
780		else {
781			prefix = strtoull(p_prefix, &p_end, 16);
782			if (*p_end != '\0') {
783				OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: illegal prefix: %s\n",
784					p_subn->opt.prefix_routes_file, line, p_prefix);
785				errors++;
786				continue;
787			}
788		}
789
790		if (strcmp(p_guid, "*") == 0)
791			guid = 0;
792		else {
793			guid = strtoull(p_guid, &p_end, 16);
794			if (*p_end != '\0' && *p_end != '#') {
795				OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: illegal GUID: %s\n",
796					p_subn->opt.prefix_routes_file, line, p_guid);
797				errors++;
798				continue;
799			}
800		}
801
802		if (append_prefix_route(p_subn, prefix, guid) != IB_SUCCESS) {
803			errors++;
804			break;
805		}
806	}
807
808	fclose(fp);
809	return (errors == 0) ? IB_SUCCESS : IB_ERROR;
810}
811
812/**********************************************************************
813 **********************************************************************/
814static void subn_verify_max_vls(unsigned *max_vls, const char *prefix, unsigned dflt)
815{
816	if (!(*max_vls) || *max_vls > 15) {
817		log_report(" Invalid Cached Option: %s_max_vls=%u: "
818			   "Using Default = %u\n", prefix, *max_vls, dflt);
819		*max_vls = dflt;
820	}
821}
822
823static void subn_verify_high_limit(int *high_limit, const char *prefix, int dflt)
824{
825	if (*high_limit < 0 || *high_limit > 255) {
826		log_report(" Invalid Cached Option: %s_high_limit=%d: "
827			   "Using Default: %d\n", prefix, *high_limit, dflt);
828		*high_limit = dflt;
829	}
830}
831
832static void subn_verify_vlarb(char **vlarb, const char *prefix,
833			      const char *suffix, char *dflt)
834{
835	char *str, *tok, *end, *ptr;
836	int count = 0;
837
838	if (*vlarb == NULL) {
839		log_report(" Invalid Cached Option: %s_vlarb_%s: "
840		"Using Default\n", prefix, suffix);
841		*vlarb = dflt;
842		return;
843	}
844
845	str = strdup(*vlarb);
846
847	tok = strtok_r(str, ",\n", &ptr);
848	while (tok) {
849		char *vl_str, *weight_str;
850
851		vl_str = tok;
852		weight_str = strchr(tok, ':');
853
854		if (weight_str) {
855			long vl, weight;
856
857			*weight_str = '\0';
858			weight_str++;
859
860			vl = strtol(vl_str, &end, 0);
861
862			if (*end)
863				log_report(" Warning: Cached Option "
864					   "%s_vlarb_%s:vl=%s"
865					   " improperly formatted\n",
866					   prefix, suffix, vl_str);
867			else if (vl < 0 || vl > 14)
868				log_report(" Warning: Cached Option "
869					   "%s_vlarb_%s:vl=%ld out of range\n",
870					   prefix, suffix, vl);
871
872			weight = strtol(weight_str, &end, 0);
873
874			if (*end)
875				log_report(" Warning: Cached Option "
876					   "%s_vlarb_%s:weight=%s "
877					   "improperly formatted\n",
878					   prefix, suffix, weight_str);
879			else if (weight < 0 || weight > 255)
880				log_report(" Warning: Cached Option "
881					   "%s_vlarb_%s:weight=%ld "
882					   "out of range\n",
883					   prefix, suffix, weight);
884		} else
885			log_report(" Warning: Cached Option "
886				   "%s_vlarb_%s:vl:weight=%s "
887				   "improperly formatted\n",
888				   prefix, suffix, tok);
889
890		count++;
891		tok = strtok_r(NULL, ",\n", &ptr);
892	}
893
894	if (count > 64)
895		log_report(" Warning: Cached Option %s_vlarb_%s: > 64 listed:"
896			   " excess vl:weight pairs will be dropped\n",
897			   prefix, suffix);
898
899	free(str);
900}
901
902static void subn_verify_sl2vl(char **sl2vl, const char *prefix, char *dflt)
903{
904	char *str, *tok, *end, *ptr;
905	int count = 0;
906
907	if (*sl2vl == NULL) {
908		log_report(" Invalid Cached Option: %s_sl2vl: Using Default\n",
909			   prefix);
910		*sl2vl = dflt;
911		return;
912	}
913
914	str = strdup(*sl2vl);
915
916	tok = strtok_r(str, ",\n", &ptr);
917	while (tok) {
918		long vl = strtol(tok, &end, 0);
919
920		if (*end)
921			log_report(" Warning: Cached Option %s_sl2vl:vl=%s "
922				   "improperly formatted\n", prefix, tok);
923		else if (vl < 0 || vl > 15)
924			log_report(" Warning: Cached Option %s_sl2vl:vl=%ld "
925				   "out of range\n", prefix, vl);
926
927		count++;
928		tok = strtok_r(NULL, ",\n", &ptr);
929	}
930
931	if (count < 16)
932		log_report(" Warning: Cached Option %s_sl2vl: < 16 VLs "
933			   "listed\n", prefix);
934
935	if (count > 16)
936		log_report(" Warning: Cached Option %s_sl2vl: > 16 listed: "
937			   "excess VLs will be dropped\n", prefix);
938
939	free(str);
940}
941
942static void subn_verify_qos_set(osm_qos_options_t *set, const char *prefix,
943				osm_qos_options_t *dflt)
944{
945	subn_verify_max_vls(&set->max_vls, prefix, dflt->max_vls);
946	subn_verify_high_limit(&set->high_limit, prefix, dflt->high_limit);
947	subn_verify_vlarb(&set->vlarb_low, prefix, "low", dflt->vlarb_low);
948	subn_verify_vlarb(&set->vlarb_high, prefix, "high", dflt->vlarb_high);
949	subn_verify_sl2vl(&set->sl2vl, prefix, dflt->sl2vl);
950}
951
952int osm_subn_verify_config(IN osm_subn_opt_t * const p_opts)
953{
954	if (p_opts->lmc > 7) {
955		log_report(" Invalid Cached Option Value:lmc = %u:"
956			   "Using Default:%u\n", p_opts->lmc, OSM_DEFAULT_LMC);
957		p_opts->lmc = OSM_DEFAULT_LMC;
958	}
959
960	if (15 < p_opts->sm_priority) {
961		log_report(" Invalid Cached Option Value:sm_priority = %u:"
962			   "Using Default:%u\n",
963			   p_opts->sm_priority, OSM_DEFAULT_SM_PRIORITY);
964		p_opts->sm_priority = OSM_DEFAULT_SM_PRIORITY;
965	}
966
967	if ((15 < p_opts->force_link_speed) ||
968	    (p_opts->force_link_speed > 7 && p_opts->force_link_speed < 15)) {
969		log_report(" Invalid Cached Option Value:force_link_speed = %u:"
970			   "Using Default:%u\n", p_opts->force_link_speed,
971			   IB_PORT_LINK_SPEED_ENABLED_MASK);
972		p_opts->force_link_speed = IB_PORT_LINK_SPEED_ENABLED_MASK;
973	}
974
975	if (strcmp(p_opts->console, OSM_DISABLE_CONSOLE)
976	    && strcmp(p_opts->console, OSM_LOCAL_CONSOLE)
977#ifdef ENABLE_OSM_CONSOLE_SOCKET
978	    && strcmp(p_opts->console, OSM_LOOPBACK_CONSOLE)
979	    && strcmp(p_opts->console, OSM_REMOTE_CONSOLE)
980#endif
981	    ) {
982		log_report(" Invalid Cached Option Value:console = %s"
983			   ", Using Default:%s\n",
984			   p_opts->console, OSM_DEFAULT_CONSOLE);
985		p_opts->console = OSM_DEFAULT_CONSOLE;
986	}
987
988	if (p_opts->qos) {
989		osm_qos_options_t dflt;
990
991		/* the default options in qos_options must be correct.
992		 * every other one need not be, b/c those will default
993		 * back to whatever is in qos_options.
994		 */
995
996		subn_set_default_qos_options(&dflt);
997
998		subn_verify_qos_set(&p_opts->qos_options, "qos", &dflt);
999		subn_verify_qos_set(&p_opts->qos_ca_options, "qos_ca",
1000				    &p_opts->qos_options);
1001		subn_verify_qos_set(&p_opts->qos_sw0_options, "qos_sw0",
1002				    &p_opts->qos_options);
1003		subn_verify_qos_set(&p_opts->qos_swe_options, "qos_swe",
1004				    &p_opts->qos_options);
1005		subn_verify_qos_set(&p_opts->qos_rtr_options, "qos_rtr",
1006				    &p_opts->qos_options);
1007	}
1008
1009#ifdef ENABLE_OSM_PERF_MGR
1010	if (p_opts->perfmgr_sweep_time_s < 1) {
1011		log_report(" Invalid Cached Option Value:perfmgr_sweep_time_s "
1012			   "= %u Using Default:%u\n",
1013			   p_opts->perfmgr_sweep_time_s,
1014			   OSM_PERFMGR_DEFAULT_SWEEP_TIME_S);
1015		p_opts->perfmgr_sweep_time_s = OSM_PERFMGR_DEFAULT_SWEEP_TIME_S;
1016	}
1017	if (p_opts->perfmgr_max_outstanding_queries < 1) {
1018		log_report(" Invalid Cached Option Value:"
1019			   "perfmgr_max_outstanding_queries = %u"
1020			   " Using Default:%u\n",
1021			   p_opts->perfmgr_max_outstanding_queries,
1022			   OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES);
1023		p_opts->perfmgr_max_outstanding_queries =
1024		    OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES;
1025	}
1026#endif
1027
1028	return 0;
1029}
1030
1031/**********************************************************************
1032 **********************************************************************/
1033int osm_subn_parse_conf_file(char *file_name, osm_subn_opt_t * const p_opts)
1034{
1035	char line[1024];
1036	FILE *opts_file;
1037	char *p_key, *p_val;
1038
1039	opts_file = fopen(file_name, "r");
1040	if (!opts_file) {
1041		if (errno == ENOENT)
1042			return 1;
1043		printf("cannot open file \'%s\': %s\n",
1044		       file_name, strerror(errno));
1045		return -1;
1046	}
1047
1048	printf(" Reading Cached Option File: %s\n", file_name);
1049	cl_log_event("OpenSM", CL_LOG_INFO, line, NULL, 0);
1050
1051	p_opts->config_file = file_name;
1052
1053	while (fgets(line, 1023, opts_file) != NULL) {
1054		/* get the first token */
1055		p_key = strtok_r(line, " \t\n", &p_val);
1056		if (!p_key)
1057			continue;
1058
1059		p_val = clean_val(p_val);
1060
1061		opts_unpack_net64("guid", p_key, p_val, &p_opts->guid);
1062
1063		opts_unpack_net64("m_key", p_key, p_val, &p_opts->m_key);
1064
1065		opts_unpack_net64("sm_key", p_key, p_val, &p_opts->sm_key);
1066
1067		opts_unpack_net64("sa_key", p_key, p_val, &p_opts->sa_key);
1068
1069		opts_unpack_net64("subnet_prefix",
1070				  p_key, p_val, &p_opts->subnet_prefix);
1071
1072		opts_unpack_net16("m_key_lease_period",
1073				  p_key, p_val, &p_opts->m_key_lease_period);
1074
1075		opts_unpack_uint32("sweep_interval",
1076				   p_key, p_val, &p_opts->sweep_interval);
1077
1078		opts_unpack_uint32("max_wire_smps",
1079				   p_key, p_val, &p_opts->max_wire_smps);
1080
1081		opts_unpack_charp("console", p_key, p_val, &p_opts->console);
1082
1083		opts_unpack_uint16("console_port",
1084				   p_key, p_val, &p_opts->console_port);
1085
1086		opts_unpack_uint32("transaction_timeout",
1087				   p_key, p_val, &p_opts->transaction_timeout);
1088
1089		opts_unpack_uint32("max_msg_fifo_timeout",
1090				   p_key, p_val, &p_opts->max_msg_fifo_timeout);
1091
1092		opts_unpack_uint8("sm_priority",
1093				  p_key, p_val, &p_opts->sm_priority);
1094
1095		opts_unpack_uint8("lmc", p_key, p_val, &p_opts->lmc);
1096
1097		opts_unpack_boolean("lmc_esp0",
1098				    p_key, p_val, &p_opts->lmc_esp0);
1099
1100		opts_unpack_uint8("max_op_vls",
1101				  p_key, p_val, &p_opts->max_op_vls);
1102
1103		opts_unpack_uint8("force_link_speed",
1104				  p_key, p_val, &p_opts->force_link_speed);
1105
1106		opts_unpack_boolean("reassign_lids",
1107				    p_key, p_val, &p_opts->reassign_lids);
1108
1109		opts_unpack_boolean("ignore_other_sm",
1110				    p_key, p_val, &p_opts->ignore_other_sm);
1111
1112		opts_unpack_boolean("single_thread",
1113				    p_key, p_val, &p_opts->single_thread);
1114
1115		opts_unpack_boolean("disable_multicast",
1116				    p_key, p_val, &p_opts->disable_multicast);
1117
1118		opts_unpack_boolean("force_log_flush",
1119				    p_key, p_val, &p_opts->force_log_flush);
1120
1121		opts_unpack_uint8("subnet_timeout",
1122				  p_key, p_val, &p_opts->subnet_timeout);
1123
1124		opts_unpack_uint8("packet_life_time",
1125				  p_key, p_val, &p_opts->packet_life_time);
1126
1127		opts_unpack_uint8("vl_stall_count",
1128				  p_key, p_val, &p_opts->vl_stall_count);
1129
1130		opts_unpack_uint8("leaf_vl_stall_count",
1131				  p_key, p_val, &p_opts->leaf_vl_stall_count);
1132
1133		opts_unpack_uint8("head_of_queue_lifetime",
1134				  p_key, p_val,
1135				  &p_opts->head_of_queue_lifetime);
1136
1137		opts_unpack_uint8("leaf_head_of_queue_lifetime", p_key, p_val,
1138				  &p_opts->leaf_head_of_queue_lifetime);
1139
1140		opts_unpack_uint8("local_phy_errors_threshold", p_key, p_val,
1141				  &p_opts->local_phy_errors_threshold);
1142
1143		opts_unpack_uint8("overrun_errors_threshold",
1144				  p_key, p_val,
1145				  &p_opts->overrun_errors_threshold);
1146
1147		opts_unpack_uint32("sminfo_polling_timeout",
1148				   p_key, p_val,
1149				   &p_opts->sminfo_polling_timeout);
1150
1151		opts_unpack_uint32("polling_retry_number",
1152				   p_key, p_val, &p_opts->polling_retry_number);
1153
1154		opts_unpack_boolean("force_heavy_sweep",
1155				    p_key, p_val, &p_opts->force_heavy_sweep);
1156
1157		opts_unpack_uint8("log_flags",
1158				  p_key, p_val, &p_opts->log_flags);
1159
1160		opts_unpack_charp("port_prof_ignore_file", p_key, p_val,
1161				  &p_opts->port_prof_ignore_file);
1162
1163		opts_unpack_boolean("port_profile_switch_nodes", p_key, p_val,
1164				    &p_opts->port_profile_switch_nodes);
1165
1166		opts_unpack_boolean("sweep_on_trap",
1167				    p_key, p_val, &p_opts->sweep_on_trap);
1168
1169		opts_unpack_charp("routing_engine",
1170				  p_key, p_val, &p_opts->routing_engine_names);
1171
1172		opts_unpack_boolean("connect_roots",
1173				    p_key, p_val, &p_opts->connect_roots);
1174
1175		opts_unpack_boolean("use_ucast_cache",
1176				    p_key, p_val, &p_opts->use_ucast_cache);
1177
1178		opts_unpack_charp("log_file", p_key, p_val, &p_opts->log_file);
1179
1180		opts_unpack_uint32("log_max_size",
1181				   p_key, p_val,
1182				   (void *) & p_opts->log_max_size);
1183		p_opts->log_max_size *= 1024 * 1024; /* convert to MB */
1184
1185		opts_unpack_charp("partition_config_file",
1186				  p_key, p_val, &p_opts->partition_config_file);
1187
1188		opts_unpack_boolean("no_partition_enforcement", p_key, p_val,
1189				    &p_opts->no_partition_enforcement);
1190
1191		opts_unpack_boolean("qos", p_key, p_val, &p_opts->qos);
1192
1193		opts_unpack_charp("qos_policy_file",
1194				  p_key, p_val, &p_opts->qos_policy_file);
1195
1196		opts_unpack_boolean("accum_log_file",
1197				    p_key, p_val, &p_opts->accum_log_file);
1198
1199		opts_unpack_charp("dump_files_dir",
1200				  p_key, p_val, &p_opts->dump_files_dir);
1201
1202		opts_unpack_charp("lid_matrix_dump_file",
1203				  p_key, p_val, &p_opts->lid_matrix_dump_file);
1204
1205		opts_unpack_charp("lfts_file",
1206				  p_key, p_val, &p_opts->lfts_file);
1207
1208		opts_unpack_charp("root_guid_file",
1209				  p_key, p_val, &p_opts->root_guid_file);
1210
1211		opts_unpack_charp("cn_guid_file",
1212				  p_key, p_val, &p_opts->cn_guid_file);
1213
1214		opts_unpack_charp("ids_guid_file",
1215				  p_key, p_val, &p_opts->ids_guid_file);
1216
1217		opts_unpack_charp("guid_routing_order_file",
1218				  p_key, p_val, &p_opts->guid_routing_order_file);
1219
1220		opts_unpack_charp("sa_db_file",
1221				  p_key, p_val, &p_opts->sa_db_file);
1222
1223		opts_unpack_boolean("exit_on_fatal",
1224				    p_key, p_val, &p_opts->exit_on_fatal);
1225
1226		opts_unpack_boolean("honor_guid2lid_file",
1227				    p_key, p_val, &p_opts->honor_guid2lid_file);
1228
1229		opts_unpack_boolean("daemon", p_key, p_val, &p_opts->daemon);
1230
1231		opts_unpack_boolean("sm_inactive",
1232				    p_key, p_val, &p_opts->sm_inactive);
1233
1234		opts_unpack_boolean("babbling_port_policy",
1235				    p_key, p_val,
1236				    &p_opts->babbling_port_policy);
1237
1238#ifdef ENABLE_OSM_PERF_MGR
1239		opts_unpack_boolean("perfmgr", p_key, p_val, &p_opts->perfmgr);
1240
1241		opts_unpack_boolean("perfmgr_redir",
1242				    p_key, p_val, &p_opts->perfmgr_redir);
1243
1244		opts_unpack_uint16("perfmgr_sweep_time_s",
1245				   p_key, p_val, &p_opts->perfmgr_sweep_time_s);
1246
1247		opts_unpack_uint32("perfmgr_max_outstanding_queries",
1248				   p_key, p_val,
1249				   &p_opts->perfmgr_max_outstanding_queries);
1250
1251		opts_unpack_charp("event_db_dump_file",
1252				  p_key, p_val, &p_opts->event_db_dump_file);
1253#endif				/* ENABLE_OSM_PERF_MGR */
1254
1255		opts_unpack_charp("event_plugin_name",
1256				  p_key, p_val, &p_opts->event_plugin_name);
1257
1258		opts_unpack_charp("node_name_map_name",
1259				  p_key, p_val, &p_opts->node_name_map_name);
1260
1261		subn_parse_qos_options("qos",
1262				       p_key, p_val, &p_opts->qos_options);
1263
1264		subn_parse_qos_options("qos_ca",
1265				       p_key, p_val, &p_opts->qos_ca_options);
1266
1267		subn_parse_qos_options("qos_sw0",
1268				       p_key, p_val, &p_opts->qos_sw0_options);
1269
1270		subn_parse_qos_options("qos_swe",
1271				       p_key, p_val, &p_opts->qos_swe_options);
1272
1273		subn_parse_qos_options("qos_rtr",
1274				       p_key, p_val, &p_opts->qos_rtr_options);
1275
1276		opts_unpack_boolean("enable_quirks",
1277				    p_key, p_val, &p_opts->enable_quirks);
1278
1279		opts_unpack_boolean("no_clients_rereg",
1280				    p_key, p_val, &p_opts->no_clients_rereg);
1281
1282		opts_unpack_charp("prefix_routes_file",
1283				  p_key, p_val, &p_opts->prefix_routes_file);
1284
1285		opts_unpack_boolean("consolidate_ipv6_snm_req",
1286				p_key, p_val, &p_opts->consolidate_ipv6_snm_req);
1287	}
1288	fclose(opts_file);
1289
1290	osm_subn_verify_config(p_opts);
1291
1292	return 0;
1293}
1294
1295int osm_subn_rescan_conf_files(IN osm_subn_t * const p_subn)
1296{
1297	FILE *opts_file;
1298	char line[1024];
1299	char *p_key, *p_val, *p_last;
1300
1301	if (!p_subn->opt.config_file)
1302		return 0;
1303
1304	opts_file = fopen(p_subn->opt.config_file, "r");
1305	if (!opts_file) {
1306		if (errno == ENOENT)
1307			return 1;
1308		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR,
1309			"cannot open file \'%s\': %s\n",
1310			p_subn->opt.config_file, strerror(errno));
1311		return -1;
1312	}
1313
1314	subn_init_qos_options(&p_subn->opt.qos_options);
1315	subn_init_qos_options(&p_subn->opt.qos_ca_options);
1316	subn_init_qos_options(&p_subn->opt.qos_sw0_options);
1317	subn_init_qos_options(&p_subn->opt.qos_swe_options);
1318	subn_init_qos_options(&p_subn->opt.qos_rtr_options);
1319
1320	while (fgets(line, 1023, opts_file) != NULL) {
1321		/* get the first token */
1322		p_key = strtok_r(line, " \t\n", &p_last);
1323		if (p_key) {
1324			p_val = strtok_r(NULL, " \t\n", &p_last);
1325
1326			subn_parse_qos_options("qos", p_key, p_val,
1327					       &p_subn->opt.qos_options);
1328
1329			subn_parse_qos_options("qos_ca", p_key, p_val,
1330					       &p_subn->opt.qos_ca_options);
1331
1332			subn_parse_qos_options("qos_sw0", p_key, p_val,
1333					       &p_subn->opt.qos_sw0_options);
1334
1335			subn_parse_qos_options("qos_swe", p_key, p_val,
1336					       &p_subn->opt.qos_swe_options);
1337
1338			subn_parse_qos_options("qos_rtr", p_key, p_val,
1339					       &p_subn->opt.qos_rtr_options);
1340
1341		}
1342	}
1343	fclose(opts_file);
1344
1345	osm_subn_verify_config(&p_subn->opt);
1346
1347	osm_parse_prefix_routes_file(p_subn);
1348
1349	return 0;
1350}
1351
1352/**********************************************************************
1353 **********************************************************************/
1354int osm_subn_output_conf(FILE *out, IN osm_subn_opt_t *const p_opts)
1355{
1356	fprintf(out,
1357		"#\n# DEVICE ATTRIBUTES OPTIONS\n#\n"
1358		"# The port GUID on which the OpenSM is running\n"
1359		"guid 0x%016" PRIx64 "\n\n"
1360		"# M_Key value sent to all ports qualifying all Set(PortInfo)\n"
1361		"m_key 0x%016" PRIx64 "\n\n"
1362		"# The lease period used for the M_Key on this subnet in [sec]\n"
1363		"m_key_lease_period %u\n\n"
1364		"# SM_Key value of the SM used for SM authentication\n"
1365		"sm_key 0x%016" PRIx64 "\n\n"
1366		"# SM_Key value to qualify rcv SA queries as 'trusted'\n"
1367		"sa_key 0x%016" PRIx64 "\n\n"
1368		"# Note that for both values above (sm_key and sa_key)\n"
1369		"# OpenSM version 3.2.1 and below used the default value '1'\n"
1370		"# in a host byte order, it is fixed now but you may need to\n"
1371		"# change the values to interoperate with old OpenSM running\n"
1372		"# on a little endian machine.\n\n"
1373		"# Subnet prefix used on this subnet\n"
1374		"subnet_prefix 0x%016" PRIx64 "\n\n"
1375		"# The LMC value used on this subnet\n"
1376		"lmc %u\n\n"
1377		"# lmc_esp0 determines whether LMC value used on subnet is used for\n"
1378		"# enhanced switch port 0. If TRUE, LMC value for subnet is used for\n"
1379		"# ESP0. Otherwise, LMC value for ESP0s is 0.\n"
1380		"lmc_esp0 %s\n\n"
1381		"# The code of maximal time a packet can live in a switch\n"
1382		"# The actual time is 4.096usec * 2^<packet_life_time>\n"
1383		"# The value 0x14 disables this mechanism\n"
1384		"packet_life_time 0x%02x\n\n"
1385		"# The number of sequential packets dropped that cause the port\n"
1386		"# to enter the VLStalled state. The result of setting this value to\n"
1387		"# zero is undefined.\n"
1388		"vl_stall_count 0x%02x\n\n"
1389		"# The number of sequential packets dropped that cause the port\n"
1390		"# to enter the VLStalled state. This value is for switch ports\n"
1391		"# driving a CA or router port. The result of setting this value\n"
1392		"# to zero is undefined.\n"
1393		"leaf_vl_stall_count 0x%02x\n\n"
1394		"# The code of maximal time a packet can wait at the head of\n"
1395		"# transmission queue.\n"
1396		"# The actual time is 4.096usec * 2^<head_of_queue_lifetime>\n"
1397		"# The value 0x14 disables this mechanism\n"
1398		"head_of_queue_lifetime 0x%02x\n\n"
1399		"# The maximal time a packet can wait at the head of queue on\n"
1400		"# switch port connected to a CA or router port\n"
1401		"leaf_head_of_queue_lifetime 0x%02x\n\n"
1402		"# Limit the maximal operational VLs\n"
1403		"max_op_vls %u\n\n"
1404		"# Force PortInfo:LinkSpeedEnabled on switch ports\n"
1405		"# If 0, don't modify PortInfo:LinkSpeedEnabled on switch port\n"
1406		"# Otherwise, use value for PortInfo:LinkSpeedEnabled on switch port\n"
1407		"# Values are (IB Spec 1.2.1, 14.2.5.6 Table 146 \"PortInfo\")\n"
1408		"#    1: 2.5 Gbps\n"
1409		"#    3: 2.5 or 5.0 Gbps\n"
1410		"#    5: 2.5 or 10.0 Gbps\n"
1411		"#    7: 2.5 or 5.0 or 10.0 Gbps\n"
1412		"#    2,4,6,8-14 Reserved\n"
1413		"#    Default 15: set to PortInfo:LinkSpeedSupported\n"
1414		"force_link_speed %u\n\n"
1415		"# The subnet_timeout code that will be set for all the ports\n"
1416		"# The actual timeout is 4.096usec * 2^<subnet_timeout>\n"
1417		"subnet_timeout %u\n\n"
1418		"# Threshold of local phy errors for sending Trap 129\n"
1419		"local_phy_errors_threshold 0x%02x\n\n"
1420		"# Threshold of credit overrun errors for sending Trap 130\n"
1421		"overrun_errors_threshold 0x%02x\n\n",
1422		cl_ntoh64(p_opts->guid),
1423		cl_ntoh64(p_opts->m_key),
1424		cl_ntoh16(p_opts->m_key_lease_period),
1425		cl_ntoh64(p_opts->sm_key),
1426		cl_ntoh64(p_opts->sa_key),
1427		cl_ntoh64(p_opts->subnet_prefix),
1428		p_opts->lmc,
1429		p_opts->lmc_esp0 ? "TRUE" : "FALSE",
1430		p_opts->packet_life_time,
1431		p_opts->vl_stall_count,
1432		p_opts->leaf_vl_stall_count,
1433		p_opts->head_of_queue_lifetime,
1434		p_opts->leaf_head_of_queue_lifetime,
1435		p_opts->max_op_vls,
1436		p_opts->force_link_speed,
1437		p_opts->subnet_timeout,
1438		p_opts->local_phy_errors_threshold,
1439		p_opts->overrun_errors_threshold);
1440
1441	fprintf(out,
1442		"#\n# PARTITIONING OPTIONS\n#\n"
1443		"# Partition configuration file to be used\n"
1444		"partition_config_file %s\n\n"
1445		"# Disable partition enforcement by switches\n"
1446		"no_partition_enforcement %s\n\n",
1447		p_opts->partition_config_file,
1448		p_opts->no_partition_enforcement ? "TRUE" : "FALSE");
1449
1450	fprintf(out,
1451		"#\n# SWEEP OPTIONS\n#\n"
1452		"# The number of seconds between subnet sweeps (0 disables it)\n"
1453		"sweep_interval %u\n\n"
1454		"# If TRUE cause all lids to be reassigned\n"
1455		"reassign_lids %s\n\n"
1456		"# If TRUE forces every sweep to be a heavy sweep\n"
1457		"force_heavy_sweep %s\n\n"
1458		"# If TRUE every trap will cause a heavy sweep.\n"
1459		"# NOTE: successive identical traps (>10) are suppressed\n"
1460		"sweep_on_trap %s\n\n",
1461		p_opts->sweep_interval,
1462		p_opts->reassign_lids ? "TRUE" : "FALSE",
1463		p_opts->force_heavy_sweep ? "TRUE" : "FALSE",
1464		p_opts->sweep_on_trap ? "TRUE" : "FALSE");
1465
1466	fprintf(out,
1467		"#\n# ROUTING OPTIONS\n#\n"
1468		"# If TRUE count switches as link subscriptions\n"
1469		"port_profile_switch_nodes %s\n\n",
1470		p_opts->port_profile_switch_nodes ? "TRUE" : "FALSE");
1471
1472	fprintf(out,
1473		"# Name of file with port guids to be ignored by port profiling\n"
1474		"port_prof_ignore_file %s\n\n", p_opts->port_prof_ignore_file ?
1475		p_opts->port_prof_ignore_file : null_str);
1476
1477	fprintf(out,
1478		"# Routing engine\n"
1479		"# Multiple routing engines can be specified separated by\n"
1480		"# commas so that specific ordering of routing algorithms will\n"
1481		"# be tried if earlier routing engines fail.\n"
1482		"# Supported engines: minhop, updn, file, ftree, lash, dor\n"
1483		"routing_engine %s\n\n", p_opts->routing_engine_names ?
1484		p_opts->routing_engine_names : null_str);
1485
1486	fprintf(out,
1487		"# Connect roots (use FALSE if unsure)\n"
1488		"connect_roots %s\n\n",
1489		p_opts->connect_roots ? "TRUE" : "FALSE");
1490
1491	fprintf(out,
1492		"# Use unicast routing cache (use FALSE if unsure)\n"
1493		"use_ucast_cache %s\n\n",
1494		p_opts->use_ucast_cache ? "TRUE" : "FALSE");
1495
1496	fprintf(out,
1497		"# Lid matrix dump file name\n"
1498		"lid_matrix_dump_file %s\n\n", p_opts->lid_matrix_dump_file ?
1499		p_opts->lid_matrix_dump_file : null_str);
1500
1501	fprintf(out,
1502		"# LFTs file name\nlfts_file %s\n\n",
1503		p_opts->lfts_file ? p_opts->lfts_file : null_str);
1504
1505	fprintf(out,
1506		"# The file holding the root node guids (for fat-tree or Up/Down)\n"
1507		"# One guid in each line\nroot_guid_file %s\n\n",
1508		p_opts->root_guid_file ? p_opts->root_guid_file : null_str);
1509
1510	fprintf(out,
1511		"# The file holding the fat-tree compute node guids\n"
1512		"# One guid in each line\ncn_guid_file %s\n\n",
1513		p_opts->cn_guid_file ? p_opts->cn_guid_file : null_str);
1514
1515	fprintf(out,
1516		"# The file holding the node ids which will be used by"
1517		" Up/Down algorithm instead\n# of GUIDs (one guid and"
1518		" id in each line)\nids_guid_file %s\n\n",
1519		p_opts->ids_guid_file ? p_opts->ids_guid_file : null_str);
1520
1521	fprintf(out,
1522		"# The file holding guid routing order guids (for MinHop and Up/Down)\n"
1523		"guid_routing_order_file %s\n\n",
1524		p_opts->guid_routing_order_file ? p_opts->guid_routing_order_file : null_str);
1525
1526	fprintf(out,
1527		"# SA database file name\nsa_db_file %s\n\n",
1528		p_opts->sa_db_file ? p_opts->sa_db_file : null_str);
1529
1530	fprintf(out,
1531		"#\n# HANDOVER - MULTIPLE SMs OPTIONS\n#\n"
1532		"# SM priority used for deciding who is the master\n"
1533		"# Range goes from 0 (lowest priority) to 15 (highest).\n"
1534		"sm_priority %u\n\n"
1535		"# If TRUE other SMs on the subnet should be ignored\n"
1536		"ignore_other_sm %s\n\n"
1537		"# Timeout in [msec] between two polls of active master SM\n"
1538		"sminfo_polling_timeout %u\n\n"
1539		"# Number of failing polls of remote SM that declares it dead\n"
1540		"polling_retry_number %u\n\n"
1541		"# If TRUE honor the guid2lid file when coming out of standby\n"
1542		"# state, if such file exists and is valid\n"
1543		"honor_guid2lid_file %s\n\n",
1544		p_opts->sm_priority,
1545		p_opts->ignore_other_sm ? "TRUE" : "FALSE",
1546		p_opts->sminfo_polling_timeout,
1547		p_opts->polling_retry_number,
1548		p_opts->honor_guid2lid_file ? "TRUE" : "FALSE");
1549
1550	fprintf(out,
1551		"#\n# TIMING AND THREADING OPTIONS\n#\n"
1552		"# Maximum number of SMPs sent in parallel\n"
1553		"max_wire_smps %u\n\n"
1554		"# The maximum time in [msec] allowed for a transaction to complete\n"
1555		"transaction_timeout %u\n\n"
1556		"# Maximal time in [msec] a message can stay in the incoming message queue.\n"
1557		"# If there is more than one message in the queue and the last message\n"
1558		"# stayed in the queue more than this value, any SA request will be\n"
1559		"# immediately returned with a BUSY status.\n"
1560		"max_msg_fifo_timeout %u\n\n"
1561		"# Use a single thread for handling SA queries\n"
1562		"single_thread %s\n\n",
1563		p_opts->max_wire_smps,
1564		p_opts->transaction_timeout,
1565		p_opts->max_msg_fifo_timeout,
1566		p_opts->single_thread ? "TRUE" : "FALSE");
1567
1568	fprintf(out,
1569		"#\n# MISC OPTIONS\n#\n"
1570		"# Daemon mode\n"
1571		"daemon %s\n\n"
1572		"# SM Inactive\n"
1573		"sm_inactive %s\n\n"
1574		"# Babbling Port Policy\n"
1575		"babbling_port_policy %s\n\n",
1576		p_opts->daemon ? "TRUE" : "FALSE",
1577		p_opts->sm_inactive ? "TRUE" : "FALSE",
1578		p_opts->babbling_port_policy ? "TRUE" : "FALSE");
1579
1580#ifdef ENABLE_OSM_PERF_MGR
1581	fprintf(out,
1582		"#\n# Performance Manager Options\n#\n"
1583		"# perfmgr enable\n"
1584		"perfmgr %s\n\n"
1585		"# perfmgr redirection enable\n"
1586		"perfmgr_redir %s\n\n"
1587		"# sweep time in seconds\n"
1588		"perfmgr_sweep_time_s %u\n\n"
1589		"# Max outstanding queries\n"
1590		"perfmgr_max_outstanding_queries %u\n\n",
1591		p_opts->perfmgr ? "TRUE" : "FALSE",
1592		p_opts->perfmgr_redir ? "TRUE" : "FALSE",
1593		p_opts->perfmgr_sweep_time_s,
1594		p_opts->perfmgr_max_outstanding_queries);
1595
1596	fprintf(out,
1597		"#\n# Event DB Options\n#\n"
1598		"# Dump file to dump the events to\n"
1599		"event_db_dump_file %s\n\n", p_opts->event_db_dump_file ?
1600		p_opts->event_db_dump_file : null_str);
1601#endif				/* ENABLE_OSM_PERF_MGR */
1602
1603	fprintf(out,
1604		"#\n# Event Plugin Options\n#\n"
1605		"event_plugin_name %s\n\n", p_opts->event_plugin_name ?
1606		p_opts->event_plugin_name : null_str);
1607
1608	fprintf(out,
1609		"#\n# Node name map for mapping node's to more descriptive node descriptions\n"
1610		"# (man ibnetdiscover for more information)\n#\n"
1611		"node_name_map_name %s\n\n", p_opts->node_name_map_name ?
1612		p_opts->node_name_map_name : null_str);
1613
1614	fprintf(out,
1615		"#\n# DEBUG FEATURES\n#\n"
1616		"# The log flags used\n"
1617		"log_flags 0x%02x\n\n"
1618		"# Force flush of the log file after each log message\n"
1619		"force_log_flush %s\n\n"
1620		"# Log file to be used\n"
1621		"log_file %s\n\n"
1622		"# Limit the size of the log file in MB. If overrun, log is restarted\n"
1623		"log_max_size %lu\n\n"
1624		"# If TRUE will accumulate the log over multiple OpenSM sessions\n"
1625		"accum_log_file %s\n\n"
1626		"# The directory to hold the file OpenSM dumps\n"
1627		"dump_files_dir %s\n\n"
1628		"# If TRUE enables new high risk options and hardware specific quirks\n"
1629		"enable_quirks %s\n\n"
1630		"# If TRUE disables client reregistration\n"
1631		"no_clients_rereg %s\n\n"
1632		"# If TRUE OpenSM should disable multicast support and\n"
1633		"# no multicast routing is performed if TRUE\n"
1634		"disable_multicast %s\n\n"
1635		"# If TRUE opensm will exit on fatal initialization issues\n"
1636		"exit_on_fatal %s\n\n" "# console [off|local"
1637#ifdef ENABLE_OSM_CONSOLE_SOCKET
1638		"|loopback|socket]\n"
1639#else
1640		"]\n"
1641#endif
1642		"console %s\n\n"
1643		"# Telnet port for console (default %d)\n"
1644		"console_port %d\n\n",
1645		p_opts->log_flags,
1646		p_opts->force_log_flush ? "TRUE" : "FALSE",
1647		p_opts->log_file,
1648		p_opts->log_max_size/1024/1024,
1649		p_opts->accum_log_file ? "TRUE" : "FALSE",
1650		p_opts->dump_files_dir,
1651		p_opts->enable_quirks ? "TRUE" : "FALSE",
1652		p_opts->no_clients_rereg ? "TRUE" : "FALSE",
1653		p_opts->disable_multicast ? "TRUE" : "FALSE",
1654		p_opts->exit_on_fatal ? "TRUE" : "FALSE",
1655		p_opts->console,
1656		OSM_DEFAULT_CONSOLE_PORT, p_opts->console_port);
1657
1658	fprintf(out,
1659		"#\n# QoS OPTIONS\n#\n"
1660		"# Enable QoS setup\n"
1661		"qos %s\n\n"
1662		"# QoS policy file to be used\n"
1663		"qos_policy_file %s\n\n",
1664		p_opts->qos ? "TRUE" : "FALSE", p_opts->qos_policy_file);
1665
1666	subn_dump_qos_options(out,
1667			      "QoS default options", "qos",
1668			      &p_opts->qos_options);
1669	fprintf(out, "\n");
1670	subn_dump_qos_options(out,
1671			      "QoS CA options", "qos_ca",
1672			      &p_opts->qos_ca_options);
1673	fprintf(out, "\n");
1674	subn_dump_qos_options(out,
1675			      "QoS Switch Port 0 options", "qos_sw0",
1676			      &p_opts->qos_sw0_options);
1677	fprintf(out, "\n");
1678	subn_dump_qos_options(out,
1679			      "QoS Switch external ports options", "qos_swe",
1680			      &p_opts->qos_swe_options);
1681	fprintf(out, "\n");
1682	subn_dump_qos_options(out,
1683			      "QoS Router ports options", "qos_rtr",
1684			      &p_opts->qos_rtr_options);
1685	fprintf(out, "\n");
1686
1687	fprintf(out,
1688		"# Prefix routes file name\n"
1689		"prefix_routes_file %s\n\n",
1690		p_opts->prefix_routes_file);
1691
1692	fprintf(out,
1693		"#\n# IPv6 Solicited Node Multicast (SNM) Options\n#\n"
1694		"consolidate_ipv6_snm_req %s\n\n",
1695		p_opts->consolidate_ipv6_snm_req ? "TRUE" : "FALSE");
1696
1697	/* optional string attributes ... */
1698
1699	return 0;
1700}
1701
1702int osm_subn_write_conf_file(char *file_name, IN osm_subn_opt_t *const p_opts)
1703{
1704	FILE *opts_file;
1705
1706	opts_file = fopen(file_name, "w");
1707	if (!opts_file) {
1708		printf("cannot open file \'%s\' for writing: %s\n",
1709			file_name, strerror(errno));
1710		return -1;
1711	}
1712
1713	if (osm_subn_output_conf(opts_file, p_opts) < 0)
1714		return -1;
1715
1716	fclose(opts_file);
1717
1718	return 0;
1719}
1720