1322774Smarkj/*
2322774Smarkj * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3322774Smarkj * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4322774Smarkj * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5322774Smarkj * Copyright (c) 2008 Xsigo Systems Inc.  All rights reserved.
6322774Smarkj * Copyright (c) 2009 System Fabric Works, Inc. All rights reserved.
7322774Smarkj * Copyright (c) 2009 HNR Consulting. All rights reserved.
8322774Smarkj * Copyright (c) 2009-2015 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
9322774Smarkj * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
10322774Smarkj *
11322774Smarkj * This software is available to you under a choice of one of two
12322774Smarkj * licenses.  You may choose to be licensed under the terms of the GNU
13322774Smarkj * General Public License (GPL) Version 2, available from the file
14322774Smarkj * COPYING in the main directory of this source tree, or the
15322774Smarkj * OpenIB.org BSD license below:
16322774Smarkj *
17322774Smarkj *     Redistribution and use in source and binary forms, with or
18322774Smarkj *     without modification, are permitted provided that the following
19322774Smarkj *     conditions are met:
20322774Smarkj *
21322774Smarkj *      - Redistributions of source code must retain the above
22322774Smarkj *        copyright notice, this list of conditions and the following
23322774Smarkj *        disclaimer.
24322774Smarkj *
25322774Smarkj *      - Redistributions in binary form must reproduce the above
26322774Smarkj *        copyright notice, this list of conditions and the following
27322774Smarkj *        disclaimer in the documentation and/or other materials
28322774Smarkj *        provided with the distribution.
29322774Smarkj *
30322774Smarkj * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31322774Smarkj * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32322774Smarkj * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33322774Smarkj * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
34322774Smarkj * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35322774Smarkj * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 * SOFTWARE.
38 *
39 */
40
41/*
42 * Abstract:
43 *    Implementation of osm_subn_t.
44 * This object represents an IBA subnet.
45 * This object is part of the opensm family of objects.
46 */
47
48#if HAVE_CONFIG_H
49#  include <config.h>
50#endif				/* HAVE_CONFIG_H */
51
52#include <string.h>
53#include <stdio.h>
54#include <stdarg.h>
55#include <limits.h>
56#include <errno.h>
57#include <ctype.h>
58#include <complib/cl_debug.h>
59#include <complib/cl_log.h>
60#include <opensm/osm_file_ids.h>
61#define FILE_ID OSM_FILE_SUBNET_C
62#include <opensm/osm_subnet.h>
63#include <opensm/osm_opensm.h>
64#include <opensm/osm_log.h>
65#include <opensm/osm_madw.h>
66#include <opensm/osm_port.h>
67#include <opensm/osm_switch.h>
68#include <opensm/osm_remote_sm.h>
69#include <opensm/osm_partition.h>
70#include <opensm/osm_node.h>
71#include <opensm/osm_guid.h>
72#include <opensm/osm_multicast.h>
73#include <opensm/osm_inform.h>
74#include <opensm/osm_console.h>
75#include <opensm/osm_perfmgr.h>
76#include <opensm/osm_congestion_control.h>
77#include <opensm/osm_event_plugin.h>
78#include <opensm/osm_qos_policy.h>
79#include <opensm/osm_service.h>
80#include <opensm/osm_db.h>
81#include <opensm/osm_db_pack.h>
82
83static const char null_str[] = "(null)";
84
85#define OPT_OFFSET(opt) offsetof(osm_subn_opt_t, opt)
86#define ARR_SIZE(a) (sizeof(a)/sizeof((a)[0]))
87
88typedef struct opt_rec {
89	const char *name;
90	unsigned long opt_offset;
91	void (*parse_fn)(osm_subn_t *p_subn, char *p_key, char *p_val_str,
92			 void *p_val1, void *p_val2,
93			 void (*)(osm_subn_t *, void *));
94	void (*setup_fn)(osm_subn_t *p_subn, void *p_val);
95	int  can_update;
96} opt_rec_t;
97
98static const char *module_name_str[] = {
99	"main.c",
100	"osm_console.c",
101	"osm_console_io.c",
102	"osm_db_files.c",
103	"osm_db_pack.c",
104	"osm_drop_mgr.c",
105	"osm_dump.c",
106	"osm_event_plugin.c",
107	"osm_guid_info_rcv.c",
108	"osm_guid_mgr.c",
109	"osm_helper.c",
110	"osm_inform.c",
111	"osm_lid_mgr.c",
112	"osm_lin_fwd_rcv.c",
113	"osm_link_mgr.c",
114	"osm_log.c",
115	"osm_mad_pool.c",
116	"osm_mcast_fwd_rcv.c",
117	"osm_mcast_mgr.c",
118	"osm_mcast_tbl.c",
119	"osm_mcm_port.c",
120	"osm_mesh.c",
121	"osm_mlnx_ext_port_info_rcv.c",
122	"osm_mtree.c",
123	"osm_multicast.c",
124	"osm_node.c",
125	"osm_node_desc_rcv.c",
126	"osm_node_info_rcv.c",
127	"osm_opensm.c",
128	"osm_perfmgr.c",
129	"osm_perfmgr_db.c",
130	"osm_pkey.c",
131	"osm_pkey_mgr.c",
132	"osm_pkey_rcv.c",
133	"osm_port.c",
134	"osm_port_info_rcv.c",
135	"osm_prtn.c",
136	"osm_prtn_config.c",
137	"osm_qos.c",
138	"osm_qos_parser_l.c",
139	"osm_qos_parser_y.c",
140	"osm_qos_policy.c",
141	"osm_remote_sm.c",
142	"osm_req.c",
143	"osm_resp.c",
144	"osm_router.c",
145	"osm_sa.c",
146	"osm_sa_class_port_info.c",
147	"osm_sa_guidinfo_record.c",
148	"osm_sa_informinfo.c",
149	"osm_sa_lft_record.c",
150	"osm_sa_link_record.c",
151	"osm_sa_mad_ctrl.c",
152	"osm_sa_mcmember_record.c",
153	"osm_sa_mft_record.c",
154	"osm_sa_multipath_record.c",
155	"osm_sa_node_record.c",
156	"osm_sa_path_record.c",
157	"osm_sa_pkey_record.c",
158	"osm_sa_portinfo_record.c",
159	"osm_sa_service_record.c",
160	"osm_sa_slvl_record.c",
161	"osm_sa_sminfo_record.c",
162	"osm_sa_sw_info_record.c",
163	"osm_sa_vlarb_record.c",
164	"osm_service.c",
165	"osm_slvl_map_rcv.c",
166	"osm_sm.c",
167	"osm_sminfo_rcv.c",
168	"osm_sm_mad_ctrl.c",
169	"osm_sm_state_mgr.c",
170	"osm_state_mgr.c",
171	"osm_subnet.c",
172	"osm_sw_info_rcv.c",
173	"osm_switch.c",
174	"osm_torus.c",
175	"osm_trap_rcv.c",
176	"osm_ucast_cache.c",
177	"osm_ucast_dnup.c",
178	"osm_ucast_file.c",
179	"osm_ucast_ftree.c",
180	"osm_ucast_lash.c",
181	"osm_ucast_mgr.c",
182	"osm_ucast_updn.c",
183	"osm_vendor_ibumad.c",
184	"osm_vl15intf.c",
185	"osm_vl_arb_rcv.c",
186	"st.c",
187	"osm_ucast_dfsssp.c",
188	"osm_congestion_control.c",
189	/* Add new module names here ... */
190	/* FILE_ID define in those modules must be identical to index here */
191	/* last FILE_ID is currently 89 */
192};
193
194#define MOD_NAME_STR_UNKNOWN_VAL (ARR_SIZE(module_name_str))
195
196static int find_module_name(const char *name, uint8_t *file_id)
197{
198	uint8_t i;
199
200	for (i = 0; i < MOD_NAME_STR_UNKNOWN_VAL; i++) {
201		if (strcmp(name, module_name_str[i]) == 0) {
202			if (file_id)
203				*file_id = i;
204			return 0;
205		}
206	}
207	return 1;
208}
209
210static void log_report(const char *fmt, ...)
211{
212	char buf[128];
213	va_list args;
214	va_start(args, fmt);
215	vsnprintf(buf, sizeof(buf), fmt, args);
216	va_end(args);
217	printf("%s", buf);
218	cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0);
219}
220
221static void log_config_value(char *name, const char *fmt, ...)
222{
223	char buf[128];
224	va_list args;
225	unsigned n;
226	va_start(args, fmt);
227	n = snprintf(buf, sizeof(buf), " Loading Cached Option:%s = ", name);
228	if (n > sizeof(buf))
229		n = sizeof(buf);
230	n += vsnprintf(buf + n, sizeof(buf) - n, fmt, args);
231	if (n > sizeof(buf) - 2)
232		n = sizeof(buf) - 2;
233	snprintf(buf + n, sizeof(buf) - n, "\n");
234	va_end(args);
235	printf("%s", buf);
236	cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0);
237}
238
239static void opts_setup_log_flags(osm_subn_t *p_subn, void *p_val)
240{
241	p_subn->p_osm->log.level = *((uint8_t *) p_val);
242}
243
244static void opts_setup_force_log_flush(osm_subn_t *p_subn, void *p_val)
245{
246	p_subn->p_osm->log.flush = *((boolean_t *) p_val);
247}
248
249static void opts_setup_accum_log_file(osm_subn_t *p_subn, void *p_val)
250{
251	p_subn->p_osm->log.accum_log_file = *((boolean_t *) p_val);
252}
253
254static void opts_setup_log_max_size(osm_subn_t *p_subn, void *p_val)
255{
256	uint32_t log_max_size = *((uint32_t *) p_val);
257
258	p_subn->p_osm->log.max_size = (unsigned long)log_max_size << 20; /* convert from MB to bytes */
259}
260
261static void opts_setup_sminfo_polling_timeout(osm_subn_t *p_subn, void *p_val)
262{
263	osm_sm_t *p_sm = &p_subn->p_osm->sm;
264	uint32_t sminfo_polling_timeout = *((uint32_t *) p_val);
265
266	cl_timer_stop(&p_sm->polling_timer);
267	cl_timer_start(&p_sm->polling_timer, sminfo_polling_timeout);
268}
269
270static void opts_setup_sm_priority(osm_subn_t *p_subn, void *p_val)
271{
272	osm_sm_t *p_sm = &p_subn->p_osm->sm;
273	uint8_t sm_priority = *((uint8_t *) p_val);
274
275	osm_set_sm_priority(p_sm, sm_priority);
276}
277
278static int opts_strtoul(uint32_t *val, IN char *p_val_str,
279			IN char *p_key, uint32_t max_value)
280{
281	char *endptr;
282	unsigned long int tmp_val;
283
284	errno = 0;
285	tmp_val = strtoul(p_val_str, &endptr, 0);
286	*val = tmp_val;
287	if (*p_val_str == '\0' || *endptr != '\0') {
288		log_report("-E- Parsing error in field %s, expected "
289			   "numeric input received: %s\n", p_key, p_val_str);
290		return -1;
291	}
292	if (tmp_val > max_value ||
293	    ((tmp_val == ULONG_MAX) && errno == ERANGE)) {
294		log_report("-E- Parsing error in field %s, value out of range\n", p_key);
295		return -1;
296	}
297	return 0;
298}
299
300static int opts_strtoull(uint64_t *val, IN char *p_val_str,
301			 IN char *p_key, uint64_t max_value)
302{
303	char *endptr;
304	unsigned long long int tmp_val;
305
306	errno = 0;
307	tmp_val = strtoull(p_val_str, &endptr, 0);
308	*val = tmp_val;
309	if (*p_val_str == '\0' || *endptr != '\0') {
310		log_report("-E- Parsing error in field %s, expected "
311			   "numeric input received: %s\n", p_key, p_val_str);
312		return -1;
313	}
314	if (tmp_val > max_value || (tmp_val == ULLONG_MAX && errno == ERANGE)) {
315		log_report("-E- Parsing error in field %s, value out of range\n", p_key);
316		return -1;
317	}
318	return 0;
319}
320
321static void opts_parse_net64(IN osm_subn_t *p_subn, IN char *p_key,
322			     IN char *p_val_str, void *p_v1, void *p_v2,
323			     void (*pfn)(osm_subn_t *, void *))
324{
325	uint64_t *p_val1 = p_v1, *p_val2 = p_v2;
326	uint64_t val;
327
328	if (opts_strtoull(&val, p_val_str, p_key, UINT64_MAX))
329		return;
330
331	if (cl_hton64(val) != *p_val1) {
332		log_config_value(p_key, "0x%016" PRIx64, val);
333		if (pfn)
334			pfn(p_subn, &val);
335		*p_val1 = *p_val2 = cl_ntoh64(val);
336	}
337}
338
339static void opts_parse_uint32(IN osm_subn_t *p_subn, IN char *p_key,
340			      IN char *p_val_str, void *p_v1, void *p_v2,
341			      void (*pfn)(osm_subn_t *, void *))
342{
343	uint32_t *p_val1 = p_v1, *p_val2 = p_v2;
344	uint32_t val;
345
346	if (opts_strtoul(&val, p_val_str, p_key, UINT32_MAX))
347		return;
348
349	if (val != *p_val1) {
350		log_config_value(p_key, "%u", val);
351		if (pfn)
352			pfn(p_subn, &val);
353		*p_val1 = *p_val2 = val;
354	}
355}
356
357static void opts_parse_net32(IN osm_subn_t *p_subn, IN char *p_key,
358			     IN char *p_val_str, void *p_v1, void *p_v2,
359			     void (*pfn)(osm_subn_t *, void *))
360{
361	uint32_t *p_val1 = p_v1, *p_val2 = p_v2;
362	uint32_t val;
363
364	if (opts_strtoul(&val, p_val_str, p_key, UINT32_MAX))
365		return;
366
367	if (cl_hton32(val) != *p_val1) {
368		log_config_value(p_key, "%u", val);
369		if (pfn)
370			pfn(p_subn, &val);
371		*p_val1 = *p_val2 = cl_hton32(val);
372	}
373}
374
375static void opts_parse_int32(IN osm_subn_t *p_subn, IN char *p_key,
376			     IN char *p_val_str, void *p_v1, void *p_v2,
377			     void (*pfn)(osm_subn_t *, void *))
378{
379	int32_t *p_val1 = p_v1, *p_val2 = p_v2;
380	int32_t val = strtol(p_val_str, NULL, 0);
381
382	if (val != *p_val1) {
383		log_config_value(p_key, "%d", val);
384		if (pfn)
385			pfn(p_subn, &val);
386		*p_val1 = *p_val2 = val;
387	}
388}
389
390static void opts_parse_uint16(IN osm_subn_t *p_subn, IN char *p_key,
391			      IN char *p_val_str, void *p_v1, void *p_v2,
392			      void (*pfn)(osm_subn_t *, void *))
393{
394	uint16_t *p_val1 = p_v1, *p_val2 = p_v2;
395	uint32_t tmp_val;
396
397	if (opts_strtoul(&tmp_val, p_val_str, p_key, UINT16_MAX))
398		return;
399
400	uint16_t val = (uint16_t) tmp_val;
401	if (val != *p_val1) {
402		log_config_value(p_key, "%u", val);
403		if (pfn)
404			pfn(p_subn, &val);
405		*p_val1 = *p_val2 = val;
406	}
407}
408
409static void opts_parse_net16(IN osm_subn_t *p_subn, IN char *p_key,
410			     IN char *p_val_str, void *p_v1, void *p_v2,
411			     void (*pfn)(osm_subn_t *, void *))
412{
413	uint16_t *p_val1 = p_v1, *p_val2 = p_v2;
414	uint32_t tmp_val;
415
416	if (opts_strtoul(&tmp_val, p_val_str, p_key, UINT16_MAX))
417		return;
418
419	uint16_t val = (uint16_t) tmp_val;
420	if (cl_hton16(val) != *p_val1) {
421		log_config_value(p_key, "0x%04x", val);
422		if (pfn)
423			pfn(p_subn, &val);
424		*p_val1 = *p_val2 = cl_hton16(val);
425	}
426}
427
428static void opts_parse_uint8(IN osm_subn_t *p_subn, IN char *p_key,
429			     IN char *p_val_str, void *p_v1, void *p_v2,
430			     void (*pfn)(osm_subn_t *, void *))
431{
432	uint8_t *p_val1 = p_v1, *p_val2 = p_v2;
433	uint32_t tmp_val;
434
435	if (opts_strtoul(&tmp_val, p_val_str, p_key, UINT8_MAX))
436		return;
437
438	uint8_t val = (uint8_t) tmp_val;
439	if (val != *p_val1) {
440		log_config_value(p_key, "%u", val);
441		if (pfn)
442			pfn(p_subn, &val);
443		*p_val1 = *p_val2 = val;
444	}
445}
446
447static void opts_parse_boolean(IN osm_subn_t *p_subn, IN char *p_key,
448			       IN char *p_val_str, void *p_v1, void *p_v2,
449			       void (*pfn)(osm_subn_t *, void *))
450{
451	boolean_t *p_val1 = p_v1, *p_val2 = p_v2;
452	boolean_t val;
453
454	if (!p_val_str)
455		return;
456
457	if (strcmp("TRUE", p_val_str))
458		val = FALSE;
459	else
460		val = TRUE;
461
462	if (val != *p_val1) {
463		log_config_value(p_key, "%s", p_val_str);
464		if (pfn)
465			pfn(p_subn, &val);
466		*p_val1 = *p_val2 = val;
467	}
468}
469
470static void opts_parse_charp(IN osm_subn_t *p_subn, IN char *p_key,
471			     IN char *p_val_str, void *p_v1, void *p_v2,
472			     void (*pfn)(osm_subn_t *, void *))
473{
474	char **p_val1 = p_v1, **p_val2 = p_v2;
475	const char *current_str = *p_val1 ? *p_val1 : null_str;
476
477	if (p_val_str && strcmp(p_val_str, current_str)) {
478		char *new;
479		log_config_value(p_key, "%s", p_val_str);
480		/* special case the "(null)" string */
481		new = strcmp(null_str, p_val_str) ? strdup(p_val_str) : NULL;
482		if (pfn)
483			pfn(p_subn, new);
484		if (*p_val1 && *p_val1 != *p_val2)
485			free(*p_val1);
486		if (*p_val2)
487			free(*p_val2);
488		*p_val1 = *p_val2 = new;
489	}
490}
491
492static void opts_parse_256bit(IN osm_subn_t *p_subn, IN char *p_key,
493			      IN char *p_val_str, void *p_v1, void *p_v2,
494			      void (*pfn)(osm_subn_t *, void *))
495{
496	uint8_t *p_val1 = p_v1, *p_val2 = p_v2;
497	uint8_t val[IB_CC_PORT_MASK_DATA_SIZE] = { 0 };
498	char tmpbuf[3] = { 0 };
499	uint8_t tmpint;
500	int numdigits = 0;
501	int startindex;
502	char *strptr = p_val_str;
503	char *ptr;
504	int i;
505
506	/* parse like it's hypothetically a 256 bit integer code
507	 *
508	 * store "big endian"
509	 */
510
511	if (!strncmp(strptr, "0x", 2) || !strncmp(strptr, "0X", 2))
512		strptr+=2;
513
514	for (ptr = strptr; *ptr; ptr++) {
515		if (!isxdigit(*ptr)) {
516			log_report("invalid hex digit in bitmask\n");
517			return;
518		}
519		numdigits++;
520	}
521
522	if (!numdigits) {
523		log_report("invalid length bitmask\n");
524		return;
525	}
526
527	/* max of 2 hex chars per byte */
528	if (numdigits > IB_CC_PORT_MASK_DATA_SIZE * 2)
529		numdigits = IB_CC_PORT_MASK_DATA_SIZE * 2;
530
531	startindex = IB_CC_PORT_MASK_DATA_SIZE - ((numdigits - 1) / 2) - 1;
532
533	if (numdigits % 2) {
534		memcpy(tmpbuf, strptr, 1);
535		strptr += 1;
536	}
537	else {
538		memcpy(tmpbuf, strptr, 2);
539		strptr += 2;
540	}
541
542	tmpint = strtoul(tmpbuf, NULL, 16);
543	val[startindex] = tmpint;
544
545	for (i = (startindex + 1); i < IB_CC_PORT_MASK_DATA_SIZE; i++) {
546		memcpy(tmpbuf, strptr, 2);
547		strptr += 2;
548		tmpint = strtoul(tmpbuf, NULL, 16);
549		val[i] = tmpint;
550	}
551
552	if (memcmp(val, p_val1, IB_CC_PORT_MASK_DATA_SIZE)) {
553		log_config_value(p_key, "%s", p_val_str);
554		if (pfn)
555			pfn(p_subn, val);
556		memcpy(p_val1, val, IB_CC_PORT_MASK_DATA_SIZE);
557		memcpy(p_val2, val, IB_CC_PORT_MASK_DATA_SIZE);
558	}
559
560}
561
562static void opts_parse_cct_entry(IN osm_subn_t *p_subn, IN char *p_key,
563				 IN char *p_val_str, void *p_v1, void *p_v2,
564				 void (*pfn)(osm_subn_t *, void *))
565{
566	osm_cct_entry_t *p_cct1 = p_v1, *p_cct2 = p_v2;
567	osm_cct_entry_t cct;
568	char buf[512] = { 0 };
569	char *ptr;
570
571	strncpy(buf, p_val_str, 511);
572
573	if (!(ptr = strchr(buf, ':'))) {
574		log_report("invalid CCT entry\n");
575		return;
576	}
577
578	*ptr = '\0';
579	ptr++;
580
581	cct.shift = strtoul(buf, NULL, 0);
582	cct.multiplier = strtoul(ptr, NULL, 0);
583
584	if (cct.shift != p_cct1->shift
585	    || cct.multiplier != p_cct1->multiplier) {
586		log_config_value(p_key, "%s", p_val_str);
587		if (pfn)
588			pfn(p_subn, &cct);
589		p_cct1->shift = p_cct2->shift = cct.shift;
590		p_cct1->multiplier = p_cct2->multiplier = cct.multiplier;
591	}
592}
593
594static void opts_parse_cc_cct(IN osm_subn_t *p_subn, IN char *p_key,
595			      IN char *p_val_str, void *p_v1, void *p_v2,
596			      void (*pfn)(osm_subn_t *, void *))
597{
598	osm_cct_t *p_val1 = p_v1, *p_val2 = p_v2;
599	const char *current_str = p_val1->input_str ? p_val1->input_str : null_str;
600
601	if (p_val_str && strcmp(p_val_str, current_str)) {
602		osm_cct_t newcct;
603		char *new;
604		unsigned int len = 0;
605		char *lasts;
606		char *tok;
607		char *ptr;
608
609		/* special case the "(null)" string */
610		new = strcmp(null_str, p_val_str) ? strdup(p_val_str) : NULL;
611
612		if (!new) {
613			log_config_value(p_key, "%s", p_val_str);
614			if (pfn)
615				pfn(p_subn, NULL);
616			memset(p_val1->entries, '\0', sizeof(p_val1->entries));
617			memset(p_val2->entries, '\0', sizeof(p_val2->entries));
618			p_val1->entries_len = p_val2->entries_len = 0;
619			p_val1->input_str = p_val2->input_str = NULL;
620			return;
621		}
622
623		memset(&newcct, '\0', sizeof(newcct));
624
625		tok = strtok_r(new, ",", &lasts);
626		while (tok && len < OSM_CCT_ENTRY_MAX) {
627
628			if (!(ptr = strchr(tok, ':'))) {
629				log_report("invalid CCT entry\n");
630				free(new);
631				return;
632			}
633			*ptr = '\0';
634			ptr++;
635
636			newcct.entries[len].shift = strtoul(tok, NULL, 0);
637			newcct.entries[len].multiplier = strtoul(ptr, NULL, 0);
638			len++;
639			tok = strtok_r(NULL, ",", &lasts);
640		}
641
642		free(new);
643
644		newcct.entries_len = len;
645		newcct.input_str = strdup(p_val_str);
646
647		log_config_value(p_key, "%s", p_val_str);
648		if (pfn)
649			pfn(p_subn, &newcct);
650		if (p_val1->input_str && p_val1->input_str != p_val2->input_str)
651			free(p_val1->input_str);
652		if (p_val2->input_str)
653			free(p_val2->input_str);
654		memcpy(p_val1->entries, newcct.entries, sizeof(newcct.entries));
655		memcpy(p_val2->entries, newcct.entries, sizeof(newcct.entries));
656		p_val1->entries_len = p_val2->entries_len = newcct.entries_len;
657		p_val1->input_str = p_val2->input_str = newcct.input_str;
658	}
659}
660
661static int parse_ca_cong_common(char *p_val_str, uint8_t *sl, unsigned int *val_offset) {
662	char *new, *lasts, *sl_str, *val_str;
663	uint8_t sltmp;
664
665	new = strcmp(null_str, p_val_str) ? strdup(p_val_str) : NULL;
666	if (!new)
667		return -1;
668
669	sl_str = strtok_r(new, " \t", &lasts);
670	val_str = strtok_r(NULL, " \t", &lasts);
671
672	if (!val_str) {
673		log_report("value must be specified in addition to SL\n");
674		free(new);
675		return -1;
676	}
677
678	sltmp = strtoul(sl_str, NULL, 0);
679	if (sltmp >= IB_CA_CONG_ENTRY_DATA_SIZE) {
680		log_report("invalid SL specified\n");
681		free(new);
682		return -1;
683	}
684
685	*sl = sltmp;
686	*val_offset = (unsigned int)(val_str - new);
687
688	free(new);
689	return 0;
690}
691
692static void opts_parse_ccti_timer(IN osm_subn_t *p_subn, IN char *p_key,
693				  IN char *p_val_str, void *p_v1, void *p_v2,
694				  void (*pfn)(osm_subn_t *, void *))
695{
696	osm_cacongestion_entry_t *p_val1 = p_v1, *p_val2 = p_v2;
697	unsigned int val_offset = 0;
698	uint8_t sl = 0;
699
700	if (parse_ca_cong_common(p_val_str, &sl, &val_offset) < 0)
701		return;
702
703	opts_parse_net16(p_subn, p_key, p_val_str + val_offset,
704			 &p_val1[sl].ccti_timer,
705			 &p_val2[sl].ccti_timer,
706			 pfn);
707}
708
709static void opts_parse_ccti_increase(IN osm_subn_t *p_subn, IN char *p_key,
710				     IN char *p_val_str, void *p_v1, void *p_v2,
711				     void (*pfn)(osm_subn_t *, void *))
712{
713	osm_cacongestion_entry_t *p_val1 = p_v1, *p_val2 = p_v2;
714	unsigned int val_offset = 0;
715	uint8_t sl = 0;
716
717	if (parse_ca_cong_common(p_val_str, &sl, &val_offset) < 0)
718		return;
719
720	opts_parse_uint8(p_subn, p_key, p_val_str + val_offset,
721			 &p_val1[sl].ccti_increase,
722			 &p_val2[sl].ccti_increase,
723			 pfn);
724}
725
726static void opts_parse_trigger_threshold(IN osm_subn_t *p_subn, IN char *p_key,
727					 IN char *p_val_str, void *p_v1, void *p_v2,
728					 void (*pfn)(osm_subn_t *, void *))
729{
730	osm_cacongestion_entry_t *p_val1 = p_v1, *p_val2 = p_v2;
731	unsigned int val_offset = 0;
732	uint8_t sl = 0;
733
734	if (parse_ca_cong_common(p_val_str, &sl, &val_offset) < 0)
735		return;
736
737	opts_parse_uint8(p_subn, p_key, p_val_str + val_offset,
738			 &p_val1[sl].trigger_threshold,
739			 &p_val2[sl].trigger_threshold,
740			 pfn);
741}
742
743static void opts_parse_ccti_min(IN osm_subn_t *p_subn, IN char *p_key,
744				IN char *p_val_str, void *p_v1, void *p_v2,
745				void (*pfn)(osm_subn_t *, void *))
746{
747	osm_cacongestion_entry_t *p_val1 = p_v1, *p_val2 = p_v2;
748	unsigned int val_offset = 0;
749	uint8_t sl = 0;
750
751	if (parse_ca_cong_common(p_val_str, &sl, &val_offset) < 0)
752		return;
753
754	opts_parse_uint8(p_subn, p_key, p_val_str + val_offset,
755			 &p_val1[sl].ccti_min,
756			 &p_val2[sl].ccti_min,
757			 pfn);
758}
759
760static const opt_rec_t opt_tbl[] = {
761	{ "guid", OPT_OFFSET(guid), opts_parse_net64, NULL, 0 },
762	{ "m_key", OPT_OFFSET(m_key), opts_parse_net64, NULL, 1 },
763	{ "sm_key", OPT_OFFSET(sm_key), opts_parse_net64, NULL, 1 },
764	{ "sa_key", OPT_OFFSET(sa_key), opts_parse_net64, NULL, 1 },
765	{ "subnet_prefix", OPT_OFFSET(subnet_prefix), opts_parse_net64, NULL, 0 },
766	{ "m_key_lease_period", OPT_OFFSET(m_key_lease_period), opts_parse_net16, NULL, 1 },
767	{ "m_key_protection_level", OPT_OFFSET(m_key_protect_bits), opts_parse_uint8, NULL, 1 },
768	{ "m_key_lookup", OPT_OFFSET(m_key_lookup), opts_parse_boolean, NULL, 1 },
769	{ "sweep_interval", OPT_OFFSET(sweep_interval), opts_parse_uint32, NULL, 1 },
770	{ "max_wire_smps", OPT_OFFSET(max_wire_smps), opts_parse_uint32, NULL, 1 },
771	{ "max_wire_smps2", OPT_OFFSET(max_wire_smps2), opts_parse_uint32, NULL, 1 },
772	{ "max_smps_timeout", OPT_OFFSET(max_smps_timeout), opts_parse_uint32, NULL, 1 },
773	{ "console", OPT_OFFSET(console), opts_parse_charp, NULL, 0 },
774	{ "console_port", OPT_OFFSET(console_port), opts_parse_uint16, NULL, 0 },
775	{ "transaction_timeout", OPT_OFFSET(transaction_timeout), opts_parse_uint32, NULL, 0 },
776	{ "transaction_retries", OPT_OFFSET(transaction_retries), opts_parse_uint32, NULL, 0 },
777	{ "max_msg_fifo_timeout", OPT_OFFSET(max_msg_fifo_timeout), opts_parse_uint32, NULL, 1 },
778	{ "sm_priority", OPT_OFFSET(sm_priority), opts_parse_uint8, opts_setup_sm_priority, 1 },
779	{ "lmc", OPT_OFFSET(lmc), opts_parse_uint8, NULL, 0 },
780	{ "lmc_esp0", OPT_OFFSET(lmc_esp0), opts_parse_boolean, NULL, 0 },
781	{ "max_op_vls", OPT_OFFSET(max_op_vls), opts_parse_uint8, NULL, 1 },
782	{ "force_link_speed", OPT_OFFSET(force_link_speed), opts_parse_uint8, NULL, 1 },
783	{ "force_link_speed_ext", OPT_OFFSET(force_link_speed_ext), opts_parse_uint8, NULL, 1 },
784	{ "fdr10", OPT_OFFSET(fdr10), opts_parse_uint8, NULL, 1 },
785	{ "reassign_lids", OPT_OFFSET(reassign_lids), opts_parse_boolean, NULL, 1 },
786	{ "ignore_other_sm", OPT_OFFSET(ignore_other_sm), opts_parse_boolean, NULL, 1 },
787	{ "single_thread", OPT_OFFSET(single_thread), opts_parse_boolean, NULL, 0 },
788	{ "disable_multicast", OPT_OFFSET(disable_multicast), opts_parse_boolean, NULL, 1 },
789	{ "subnet_timeout", OPT_OFFSET(subnet_timeout), opts_parse_uint8, NULL, 1 },
790	{ "packet_life_time", OPT_OFFSET(packet_life_time), opts_parse_uint8, NULL, 1 },
791	{ "vl_stall_count", OPT_OFFSET(vl_stall_count), opts_parse_uint8, NULL, 1 },
792	{ "leaf_vl_stall_count", OPT_OFFSET(leaf_vl_stall_count), opts_parse_uint8, NULL, 1 },
793	{ "head_of_queue_lifetime", OPT_OFFSET(head_of_queue_lifetime), opts_parse_uint8, NULL, 1 },
794	{ "leaf_head_of_queue_lifetime", OPT_OFFSET(leaf_head_of_queue_lifetime), opts_parse_uint8, NULL, 1 },
795	{ "local_phy_errors_threshold", OPT_OFFSET(local_phy_errors_threshold), opts_parse_uint8, NULL, 1 },
796	{ "overrun_errors_threshold", OPT_OFFSET(overrun_errors_threshold), opts_parse_uint8, NULL, 1 },
797	{ "use_mfttop", OPT_OFFSET(use_mfttop), opts_parse_boolean, NULL, 1},
798	{ "sminfo_polling_timeout", OPT_OFFSET(sminfo_polling_timeout), opts_parse_uint32, opts_setup_sminfo_polling_timeout, 1 },
799	{ "polling_retry_number", OPT_OFFSET(polling_retry_number), opts_parse_uint32, NULL, 1 },
800	{ "force_heavy_sweep", OPT_OFFSET(force_heavy_sweep), opts_parse_boolean, NULL, 1 },
801	{ "port_prof_ignore_file", OPT_OFFSET(port_prof_ignore_file), opts_parse_charp, NULL, 0 },
802	{ "hop_weights_file", OPT_OFFSET(hop_weights_file), opts_parse_charp, NULL, 0 },
803	{ "dimn_ports_file", OPT_OFFSET(port_search_ordering_file), opts_parse_charp, NULL, 0 },
804	{ "port_search_ordering_file", OPT_OFFSET(port_search_ordering_file), opts_parse_charp, NULL, 0 },
805	{ "port_profile_switch_nodes", OPT_OFFSET(port_profile_switch_nodes), opts_parse_boolean, NULL, 1 },
806	{ "sweep_on_trap", OPT_OFFSET(sweep_on_trap), opts_parse_boolean, NULL, 1 },
807	{ "routing_engine", OPT_OFFSET(routing_engine_names), opts_parse_charp, NULL, 0 },
808	{ "connect_roots", OPT_OFFSET(connect_roots), opts_parse_boolean, NULL, 1 },
809	{ "use_ucast_cache", OPT_OFFSET(use_ucast_cache), opts_parse_boolean, NULL, 0 },
810	{ "log_file", OPT_OFFSET(log_file), opts_parse_charp, NULL, 0 },
811	{ "log_max_size", OPT_OFFSET(log_max_size), opts_parse_uint32, opts_setup_log_max_size, 1 },
812	{ "log_flags", OPT_OFFSET(log_flags), opts_parse_uint8, opts_setup_log_flags, 1 },
813	{ "force_log_flush", OPT_OFFSET(force_log_flush), opts_parse_boolean, opts_setup_force_log_flush, 1 },
814	{ "accum_log_file", OPT_OFFSET(accum_log_file), opts_parse_boolean, opts_setup_accum_log_file, 1 },
815	{ "partition_config_file", OPT_OFFSET(partition_config_file), opts_parse_charp, NULL, 0 },
816	{ "no_partition_enforcement", OPT_OFFSET(no_partition_enforcement), opts_parse_boolean, NULL, 1 },
817	{ "part_enforce", OPT_OFFSET(part_enforce), opts_parse_charp, NULL, 1 },
818	{ "allow_both_pkeys", OPT_OFFSET(allow_both_pkeys), opts_parse_boolean, NULL, 0 },
819	{ "sm_assigned_guid", OPT_OFFSET(sm_assigned_guid), opts_parse_uint8, NULL, 1 },
820	{ "qos", OPT_OFFSET(qos), opts_parse_boolean, NULL, 1 },
821	{ "qos_policy_file", OPT_OFFSET(qos_policy_file), opts_parse_charp, NULL, 0 },
822	{ "suppress_sl2vl_mad_status_errors", OPT_OFFSET(suppress_sl2vl_mad_status_errors), opts_parse_boolean, NULL, 1 },
823	{ "dump_files_dir", OPT_OFFSET(dump_files_dir), opts_parse_charp, NULL, 0 },
824	{ "lid_matrix_dump_file", OPT_OFFSET(lid_matrix_dump_file), opts_parse_charp, NULL, 0 },
825	{ "lfts_file", OPT_OFFSET(lfts_file), opts_parse_charp, NULL, 0 },
826	{ "root_guid_file", OPT_OFFSET(root_guid_file), opts_parse_charp, NULL, 0 },
827	{ "cn_guid_file", OPT_OFFSET(cn_guid_file), opts_parse_charp, NULL, 0 },
828	{ "io_guid_file", OPT_OFFSET(io_guid_file), opts_parse_charp, NULL, 0 },
829	{ "port_shifting", OPT_OFFSET(port_shifting), opts_parse_boolean, NULL, 1 },
830	{ "scatter_ports", OPT_OFFSET(scatter_ports), opts_parse_uint32, NULL, 1 },
831	{ "max_reverse_hops", OPT_OFFSET(max_reverse_hops), opts_parse_uint16, NULL, 0 },
832	{ "ids_guid_file", OPT_OFFSET(ids_guid_file), opts_parse_charp, NULL, 0 },
833	{ "guid_routing_order_file", OPT_OFFSET(guid_routing_order_file), opts_parse_charp, NULL, 0 },
834	{ "guid_routing_order_no_scatter", OPT_OFFSET(guid_routing_order_no_scatter), opts_parse_boolean, NULL, 0 },
835	{ "sa_db_file", OPT_OFFSET(sa_db_file), opts_parse_charp, NULL, 0 },
836	{ "sa_db_dump", OPT_OFFSET(sa_db_dump), opts_parse_boolean, NULL, 1 },
837	{ "torus_config", OPT_OFFSET(torus_conf_file), opts_parse_charp, NULL, 1 },
838	{ "do_mesh_analysis", OPT_OFFSET(do_mesh_analysis), opts_parse_boolean, NULL, 1 },
839	{ "exit_on_fatal", OPT_OFFSET(exit_on_fatal), opts_parse_boolean, NULL, 1 },
840	{ "honor_guid2lid_file", OPT_OFFSET(honor_guid2lid_file), opts_parse_boolean, NULL, 1 },
841	{ "daemon", OPT_OFFSET(daemon), opts_parse_boolean, NULL, 0 },
842	{ "sm_inactive", OPT_OFFSET(sm_inactive), opts_parse_boolean, NULL, 1 },
843	{ "babbling_port_policy", OPT_OFFSET(babbling_port_policy), opts_parse_boolean, NULL, 1 },
844	{ "drop_event_subscriptions", OPT_OFFSET(drop_event_subscriptions), opts_parse_boolean, NULL, 1 },
845	{ "ipoib_mcgroup_creation_validation", OPT_OFFSET(ipoib_mcgroup_creation_validation), opts_parse_boolean, NULL, 1 },
846	{ "mcgroup_join_validation", OPT_OFFSET(mcgroup_join_validation), opts_parse_boolean, NULL, 1 },
847	{ "use_optimized_slvl", OPT_OFFSET(use_optimized_slvl), opts_parse_boolean, NULL, 1 },
848	{ "fsync_high_avail_files", OPT_OFFSET(fsync_high_avail_files), opts_parse_boolean, NULL, 1 },
849#ifdef ENABLE_OSM_PERF_MGR
850	{ "perfmgr", OPT_OFFSET(perfmgr), opts_parse_boolean, NULL, 0 },
851	{ "perfmgr_redir", OPT_OFFSET(perfmgr_redir), opts_parse_boolean, NULL, 0 },
852	{ "perfmgr_sweep_time_s", OPT_OFFSET(perfmgr_sweep_time_s), opts_parse_uint16, NULL, 0 },
853	{ "perfmgr_max_outstanding_queries", OPT_OFFSET(perfmgr_max_outstanding_queries), opts_parse_uint32, NULL, 0 },
854	{ "perfmgr_ignore_cas", OPT_OFFSET(perfmgr_ignore_cas), opts_parse_boolean, NULL, 0 },
855	{ "event_db_dump_file", OPT_OFFSET(event_db_dump_file), opts_parse_charp, NULL, 0 },
856	{ "perfmgr_rm_nodes", OPT_OFFSET(perfmgr_rm_nodes), opts_parse_boolean, NULL, 0 },
857	{ "perfmgr_log_errors", OPT_OFFSET(perfmgr_log_errors), opts_parse_boolean, NULL, 0 },
858	{ "perfmgr_query_cpi", OPT_OFFSET(perfmgr_query_cpi), opts_parse_boolean, NULL, 0 },
859	{ "perfmgr_xmit_wait_log", OPT_OFFSET(perfmgr_xmit_wait_log), opts_parse_boolean, NULL, 0 },
860	{ "perfmgr_xmit_wait_threshold", OPT_OFFSET(perfmgr_xmit_wait_threshold), opts_parse_uint32, NULL, 0 },
861#endif				/* ENABLE_OSM_PERF_MGR */
862	{ "event_plugin_name", OPT_OFFSET(event_plugin_name), opts_parse_charp, NULL, 0 },
863	{ "event_plugin_options", OPT_OFFSET(event_plugin_options), opts_parse_charp, NULL, 0 },
864	{ "node_name_map_name", OPT_OFFSET(node_name_map_name), opts_parse_charp, NULL, 0 },
865	{ "qos_max_vls", OPT_OFFSET(qos_options.max_vls), opts_parse_uint32, NULL, 1 },
866	{ "qos_high_limit", OPT_OFFSET(qos_options.high_limit), opts_parse_int32, NULL, 1 },
867	{ "qos_vlarb_high", OPT_OFFSET(qos_options.vlarb_high), opts_parse_charp, NULL, 1 },
868	{ "qos_vlarb_low", OPT_OFFSET(qos_options.vlarb_low), opts_parse_charp, NULL, 1 },
869	{ "qos_sl2vl", OPT_OFFSET(qos_options.sl2vl), opts_parse_charp, NULL, 1 },
870	{ "qos_ca_max_vls", OPT_OFFSET(qos_ca_options.max_vls), opts_parse_uint32, NULL, 1 },
871	{ "qos_ca_high_limit", OPT_OFFSET(qos_ca_options.high_limit), opts_parse_int32, NULL, 1 },
872	{ "qos_ca_vlarb_high", OPT_OFFSET(qos_ca_options.vlarb_high), opts_parse_charp, NULL, 1 },
873	{ "qos_ca_vlarb_low", OPT_OFFSET(qos_ca_options.vlarb_low), opts_parse_charp, NULL, 1 },
874	{ "qos_ca_sl2vl", OPT_OFFSET(qos_ca_options.sl2vl), opts_parse_charp, NULL, 1 },
875	{ "qos_sw0_max_vls", OPT_OFFSET(qos_sw0_options.max_vls), opts_parse_uint32, NULL, 1 },
876	{ "qos_sw0_high_limit", OPT_OFFSET(qos_sw0_options.high_limit), opts_parse_int32, NULL, 1 },
877	{ "qos_sw0_vlarb_high", OPT_OFFSET(qos_sw0_options.vlarb_high), opts_parse_charp, NULL, 1 },
878	{ "qos_sw0_vlarb_low", OPT_OFFSET(qos_sw0_options.vlarb_low), opts_parse_charp, NULL, 1 },
879	{ "qos_sw0_sl2vl", OPT_OFFSET(qos_sw0_options.sl2vl), opts_parse_charp, NULL, 1 },
880	{ "qos_swe_max_vls", OPT_OFFSET(qos_swe_options.max_vls), opts_parse_uint32, NULL, 1 },
881	{ "qos_swe_high_limit", OPT_OFFSET(qos_swe_options.high_limit), opts_parse_int32, NULL, 1 },
882	{ "qos_swe_vlarb_high", OPT_OFFSET(qos_swe_options.vlarb_high), opts_parse_charp, NULL, 1 },
883	{ "qos_swe_vlarb_low", OPT_OFFSET(qos_swe_options.vlarb_low), opts_parse_charp, NULL, 1 },
884	{ "qos_swe_sl2vl", OPT_OFFSET(qos_swe_options.sl2vl), opts_parse_charp, NULL, 1 },
885	{ "qos_rtr_max_vls", OPT_OFFSET(qos_rtr_options.max_vls), opts_parse_uint32, NULL, 1 },
886	{ "qos_rtr_high_limit", OPT_OFFSET(qos_rtr_options.high_limit), opts_parse_int32, NULL, 1 },
887	{ "qos_rtr_vlarb_high", OPT_OFFSET(qos_rtr_options.vlarb_high), opts_parse_charp, NULL, 1 },
888	{ "qos_rtr_vlarb_low", OPT_OFFSET(qos_rtr_options.vlarb_low), opts_parse_charp, NULL, 1 },
889	{ "qos_rtr_sl2vl", OPT_OFFSET(qos_rtr_options.sl2vl), opts_parse_charp, NULL, 1 },
890	{ "congestion_control", OPT_OFFSET(congestion_control), opts_parse_boolean, NULL, 1 },
891	{ "cc_key", OPT_OFFSET(cc_key), opts_parse_net64, NULL, 0},
892	{ "cc_max_outstanding_mads", OPT_OFFSET(cc_max_outstanding_mads), opts_parse_uint32, NULL, 0 },
893	{ "cc_sw_cong_setting_control_map", OPT_OFFSET(cc_sw_cong_setting_control_map), opts_parse_net32, NULL, 1},
894	{ "cc_sw_cong_setting_victim_mask", OPT_OFFSET(cc_sw_cong_setting_victim_mask), opts_parse_256bit, NULL, 1},
895	{ "cc_sw_cong_setting_credit_mask", OPT_OFFSET(cc_sw_cong_setting_credit_mask), opts_parse_256bit, NULL, 1},
896	{ "cc_sw_cong_setting_threshold", OPT_OFFSET(cc_sw_cong_setting_threshold), opts_parse_uint8, NULL, 1},
897	{ "cc_sw_cong_setting_packet_size", OPT_OFFSET(cc_sw_cong_setting_packet_size), opts_parse_uint8, NULL, 1},
898	{ "cc_sw_cong_setting_credit_starvation_threshold", OPT_OFFSET(cc_sw_cong_setting_credit_starvation_threshold), opts_parse_uint8, NULL, 1},
899	{ "cc_sw_cong_setting_credit_starvation_return_delay", OPT_OFFSET(cc_sw_cong_setting_credit_starvation_return_delay), opts_parse_cct_entry, NULL, 1},
900	{ "cc_sw_cong_setting_marking_rate", OPT_OFFSET(cc_sw_cong_setting_marking_rate), opts_parse_net16, NULL, 1},
901	{ "cc_ca_cong_setting_port_control", OPT_OFFSET(cc_ca_cong_setting_port_control), opts_parse_net16, NULL, 1},
902	{ "cc_ca_cong_setting_control_map", OPT_OFFSET(cc_ca_cong_setting_control_map), opts_parse_net16, NULL, 1},
903	{ "cc_ca_cong_setting_ccti_timer", OPT_OFFSET(cc_ca_cong_entries), opts_parse_ccti_timer, NULL, 1},
904	{ "cc_ca_cong_setting_ccti_increase", OPT_OFFSET(cc_ca_cong_entries), opts_parse_ccti_increase, NULL, 1},
905	{ "cc_ca_cong_setting_trigger_threshold", OPT_OFFSET(cc_ca_cong_entries), opts_parse_trigger_threshold, NULL, 1},
906	{ "cc_ca_cong_setting_ccti_min", OPT_OFFSET(cc_ca_cong_entries), opts_parse_ccti_min, NULL, 1},
907	{ "cc_cct", OPT_OFFSET(cc_cct), opts_parse_cc_cct, NULL, 1},
908	{ "enable_quirks", OPT_OFFSET(enable_quirks), opts_parse_boolean, NULL, 1 },
909	{ "no_clients_rereg", OPT_OFFSET(no_clients_rereg), opts_parse_boolean, NULL, 1 },
910	{ "prefix_routes_file", OPT_OFFSET(prefix_routes_file), opts_parse_charp, NULL, 0 },
911	{ "consolidate_ipv6_snm_req", OPT_OFFSET(consolidate_ipv6_snm_req), opts_parse_boolean, NULL, 1 },
912	{ "lash_start_vl", OPT_OFFSET(lash_start_vl), opts_parse_uint8, NULL, 1 },
913	{ "sm_sl", OPT_OFFSET(sm_sl), opts_parse_uint8, NULL, 1 },
914	{ "log_prefix", OPT_OFFSET(log_prefix), opts_parse_charp, NULL, 1 },
915	{ "per_module_logging_file", OPT_OFFSET(per_module_logging_file), opts_parse_charp, NULL, 0 },
916	{ "quasi_ftree_indexing", OPT_OFFSET(quasi_ftree_indexing), opts_parse_boolean, NULL, 1 },
917	{0}
918};
919
920static int compar_mgids(const void *m1, const void *m2)
921{
922	return memcmp(m1, m2, sizeof(ib_gid_t));
923}
924
925static void subn_validate_g2m(osm_subn_t *p_subn)
926{
927	cl_qlist_t guids;
928	osm_db_guid_elem_t *p_item;
929	uint64_t mkey;
930	boolean_t valid_entry;
931
932	OSM_LOG_ENTER(&(p_subn->p_osm->log));
933	cl_qlist_init(&guids);
934
935	if (osm_db_guid2mkey_guids(p_subn->p_g2m, &guids)) {
936		OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR, "ERR 7506: "
937			"could not get mkey guid list\n");
938		goto Exit;
939	}
940
941	while ((p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids))
942	       != (osm_db_guid_elem_t *) cl_qlist_end(&guids)) {
943		valid_entry = TRUE;
944
945		if (p_item->guid == 0) {
946			OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
947				"ERR 7507: found invalid zero guid");
948			valid_entry = FALSE;
949		} else if (osm_db_guid2mkey_get(p_subn->p_g2m, p_item->guid,
950						&mkey)) {
951			OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
952				"ERR 7508: could not get mkey for guid:0x%016"
953				PRIx64 "\n", p_item->guid);
954			valid_entry = FALSE;
955		}
956
957		if (valid_entry == FALSE) {
958			if (osm_db_guid2mkey_delete(p_subn->p_g2m,
959						    p_item->guid))
960				OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
961					"ERR 7509: failed to delete entry for "
962					"guid:0x%016" PRIx64 "\n",
963					p_item->guid);
964		}
965		free(p_item);
966	}
967
968Exit:
969	OSM_LOG_EXIT(&(p_subn->p_osm->log));
970}
971
972static void subn_validate_neighbor(osm_subn_t *p_subn)
973{
974	cl_qlist_t entries;
975	osm_db_neighbor_elem_t *p_item;
976	boolean_t valid_entry;
977	uint64_t guid;
978	uint8_t port;
979
980	OSM_LOG_ENTER(&(p_subn->p_osm->log));
981	cl_qlist_init(&entries);
982
983	if (osm_db_neighbor_guids(p_subn->p_neighbor, &entries)) {
984		OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR, "ERR 7512: "
985			"could not get neighbor entry list\n");
986		goto Exit;
987	}
988
989	while ((p_item =
990		(osm_db_neighbor_elem_t *) cl_qlist_remove_head(&entries))
991	       != (osm_db_neighbor_elem_t *) cl_qlist_end(&entries)) {
992		valid_entry = TRUE;
993
994		OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_DEBUG,
995			"Validating neighbor for guid:0x%016" PRIx64
996			", port %d\n",
997			p_item->guid, p_item->portnum);
998		if (p_item->guid == 0) {
999			OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
1000				"ERR 7513: found invalid zero guid\n");
1001			valid_entry = FALSE;
1002		} else if (p_item->portnum == 0) {
1003			OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
1004				"ERR 7514: found invalid zero port for "
1005				"guid: 0x%016" PRIx64 "\n",
1006				p_item->guid);
1007			valid_entry = FALSE;
1008		} else if (osm_db_neighbor_get(p_subn->p_neighbor,
1009					       p_item->guid, p_item->portnum,
1010					       &guid, &port)) {
1011			OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
1012				"ERR 7515: could not find neighbor for "
1013				"guid: 0x%016" PRIx64 ", port %d\n",
1014				p_item->guid, p_item->portnum);
1015			valid_entry = FALSE;
1016		} else if (guid == 0) {
1017			OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
1018				"ERR 7516: found invalid neighbor "
1019				"zero guid for guid: 0x%016" PRIx64
1020				", port %d\n",
1021				p_item->guid, p_item->portnum);
1022			valid_entry = FALSE;
1023		} else if (port == 0) {
1024			OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
1025				"ERR 7517: found invalid neighbor "
1026				"zero port for guid: 0x%016" PRIx64
1027				", port %d\n",
1028				p_item->guid, p_item->portnum);
1029			valid_entry = FALSE;
1030		} else if (osm_db_neighbor_get(p_subn->p_neighbor,
1031					       guid, port, &guid, &port) ||
1032			   guid != p_item->guid || port != p_item->portnum) {
1033			OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
1034				"ERR 7518: neighbor does not point "
1035				"back at us (guid: 0x%016" PRIx64
1036				", port %d)\n",
1037				p_item->guid, p_item->portnum);
1038			valid_entry = FALSE;
1039		}
1040
1041		if (valid_entry == FALSE) {
1042			if (osm_db_neighbor_delete(p_subn->p_neighbor,
1043						   p_item->guid,
1044						   p_item->portnum))
1045				OSM_LOG(&(p_subn->p_osm->log), OSM_LOG_ERROR,
1046					"ERR 7519: failed to delete entry for "
1047					"guid:0x%016" PRIx64 " port:%u\n",
1048					p_item->guid, p_item->portnum);
1049		}
1050		free(p_item);
1051	}
1052
1053Exit:
1054	OSM_LOG_EXIT(&(p_subn->p_osm->log));
1055}
1056
1057void osm_subn_construct(IN osm_subn_t * p_subn)
1058{
1059	memset(p_subn, 0, sizeof(*p_subn));
1060	cl_ptr_vector_construct(&p_subn->port_lid_tbl);
1061	cl_qmap_init(&p_subn->sw_guid_tbl);
1062	cl_qmap_init(&p_subn->node_guid_tbl);
1063	cl_qmap_init(&p_subn->port_guid_tbl);
1064	cl_qmap_init(&p_subn->alias_port_guid_tbl);
1065	cl_qmap_init(&p_subn->assigned_guids_tbl);
1066	cl_qmap_init(&p_subn->sm_guid_tbl);
1067	cl_qlist_init(&p_subn->sa_sr_list);
1068	cl_qlist_init(&p_subn->sa_infr_list);
1069	cl_qlist_init(&p_subn->alias_guid_list);
1070	cl_qlist_init(&p_subn->prefix_routes_list);
1071	cl_qmap_init(&p_subn->rtr_guid_tbl);
1072	cl_qmap_init(&p_subn->prtn_pkey_tbl);
1073	cl_fmap_init(&p_subn->mgrp_mgid_tbl, compar_mgids);
1074}
1075
1076static void subn_destroy_qos_options(osm_qos_options_t *opt)
1077{
1078	free(opt->vlarb_high);
1079	free(opt->vlarb_low);
1080	free(opt->sl2vl);
1081}
1082
1083static void subn_opt_destroy(IN osm_subn_opt_t * p_opt)
1084{
1085	free(p_opt->console);
1086	free(p_opt->port_prof_ignore_file);
1087	free(p_opt->hop_weights_file);
1088	free(p_opt->port_search_ordering_file);
1089	free(p_opt->routing_engine_names);
1090	free(p_opt->log_file);
1091	free(p_opt->partition_config_file);
1092	free(p_opt->qos_policy_file);
1093	free(p_opt->dump_files_dir);
1094	free(p_opt->part_enforce);
1095	free(p_opt->lid_matrix_dump_file);
1096	free(p_opt->lfts_file);
1097	free(p_opt->root_guid_file);
1098	free(p_opt->cn_guid_file);
1099	free(p_opt->io_guid_file);
1100	free(p_opt->ids_guid_file);
1101	free(p_opt->guid_routing_order_file);
1102	free(p_opt->sa_db_file);
1103	free(p_opt->torus_conf_file);
1104#ifdef ENABLE_OSM_PERF_MGR
1105	free(p_opt->event_db_dump_file);
1106#endif /* ENABLE_OSM_PERF_MGR */
1107	free(p_opt->event_plugin_name);
1108	free(p_opt->event_plugin_options);
1109	free(p_opt->node_name_map_name);
1110	free(p_opt->prefix_routes_file);
1111	free(p_opt->log_prefix);
1112	subn_destroy_qos_options(&p_opt->qos_options);
1113	subn_destroy_qos_options(&p_opt->qos_ca_options);
1114	subn_destroy_qos_options(&p_opt->qos_sw0_options);
1115	subn_destroy_qos_options(&p_opt->qos_swe_options);
1116	subn_destroy_qos_options(&p_opt->qos_rtr_options);
1117	free(p_opt->cc_cct.input_str);
1118}
1119
1120void osm_subn_destroy(IN osm_subn_t * p_subn)
1121{
1122	int i;
1123	osm_node_t *p_node, *p_next_node;
1124	osm_assigned_guids_t *p_assigned_guids, *p_next_assigned_guids;
1125	osm_alias_guid_t *p_alias_guid, *p_next_alias_guid;
1126	osm_port_t *p_port, *p_next_port;
1127	osm_switch_t *p_sw, *p_next_sw;
1128	osm_remote_sm_t *p_rsm, *p_next_rsm;
1129	osm_prtn_t *p_prtn, *p_next_prtn;
1130	osm_infr_t *p_infr, *p_next_infr;
1131	osm_svcr_t *p_svcr, *p_next_svcr;
1132
1133	/* it might be a good idea to de-allocate all known objects */
1134	p_next_node = (osm_node_t *) cl_qmap_head(&p_subn->node_guid_tbl);
1135	while (p_next_node !=
1136	       (osm_node_t *) cl_qmap_end(&p_subn->node_guid_tbl)) {
1137		p_node = p_next_node;
1138		p_next_node = (osm_node_t *) cl_qmap_next(&p_node->map_item);
1139		osm_node_delete(&p_node);
1140	}
1141
1142	p_next_assigned_guids = (osm_assigned_guids_t *) cl_qmap_head(&p_subn->assigned_guids_tbl);
1143	while (p_next_assigned_guids !=
1144	       (osm_assigned_guids_t *) cl_qmap_end(&p_subn->assigned_guids_tbl)) {
1145		p_assigned_guids = p_next_assigned_guids;
1146		p_next_assigned_guids = (osm_assigned_guids_t *) cl_qmap_next(&p_assigned_guids->map_item);
1147		osm_assigned_guids_delete(&p_assigned_guids);
1148	}
1149
1150	p_next_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&p_subn->alias_port_guid_tbl);
1151	while (p_next_alias_guid !=
1152	       (osm_alias_guid_t *) cl_qmap_end(&p_subn->alias_port_guid_tbl)) {
1153		p_alias_guid = p_next_alias_guid;
1154		p_next_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
1155		osm_alias_guid_delete(&p_alias_guid);
1156	}
1157
1158	while (cl_qlist_count(&p_subn->alias_guid_list))
1159		osm_guid_work_obj_delete((osm_guidinfo_work_obj_t *) cl_qlist_remove_head(&p_subn->alias_guid_list));
1160
1161	p_next_port = (osm_port_t *) cl_qmap_head(&p_subn->port_guid_tbl);
1162	while (p_next_port !=
1163	       (osm_port_t *) cl_qmap_end(&p_subn->port_guid_tbl)) {
1164		p_port = p_next_port;
1165		p_next_port = (osm_port_t *) cl_qmap_next(&p_port->map_item);
1166		osm_port_delete(&p_port);
1167	}
1168
1169	p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
1170	while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) {
1171		p_sw = p_next_sw;
1172		p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item);
1173		osm_switch_delete(&p_sw);
1174	}
1175
1176	p_next_rsm = (osm_remote_sm_t *) cl_qmap_head(&p_subn->sm_guid_tbl);
1177	while (p_next_rsm !=
1178	       (osm_remote_sm_t *) cl_qmap_end(&p_subn->sm_guid_tbl)) {
1179		p_rsm = p_next_rsm;
1180		p_next_rsm = (osm_remote_sm_t *) cl_qmap_next(&p_rsm->map_item);
1181		free(p_rsm);
1182	}
1183
1184	p_next_prtn = (osm_prtn_t *) cl_qmap_head(&p_subn->prtn_pkey_tbl);
1185	while (p_next_prtn !=
1186	       (osm_prtn_t *) cl_qmap_end(&p_subn->prtn_pkey_tbl)) {
1187		p_prtn = p_next_prtn;
1188		p_next_prtn = (osm_prtn_t *) cl_qmap_next(&p_prtn->map_item);
1189		osm_prtn_delete(p_subn, &p_prtn);
1190	}
1191
1192	cl_fmap_remove_all(&p_subn->mgrp_mgid_tbl);
1193
1194	for (i = 0; i <= p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO;
1195	     i++)
1196		if (p_subn->mboxes[i])
1197			osm_mgrp_box_delete(p_subn->mboxes[i]);
1198
1199	p_next_infr = (osm_infr_t *) cl_qlist_head(&p_subn->sa_infr_list);
1200	while (p_next_infr !=
1201	       (osm_infr_t *) cl_qlist_end(&p_subn->sa_infr_list)) {
1202		p_infr = p_next_infr;
1203		p_next_infr = (osm_infr_t *) cl_qlist_next(&p_infr->list_item);
1204		osm_infr_delete(p_infr);
1205	}
1206
1207	p_next_svcr = (osm_svcr_t *) cl_qlist_head(&p_subn->sa_sr_list);
1208	while (p_next_svcr !=
1209	       (osm_svcr_t *) cl_qlist_end(&p_subn->sa_sr_list)) {
1210		p_svcr = p_next_svcr;
1211		p_next_svcr = (osm_svcr_t *) cl_qlist_next(&p_svcr->list_item);
1212		osm_svcr_delete(p_svcr);
1213	}
1214
1215	cl_ptr_vector_destroy(&p_subn->port_lid_tbl);
1216
1217	osm_qos_policy_destroy(p_subn->p_qos_policy);
1218
1219	while (!cl_is_qlist_empty(&p_subn->prefix_routes_list)) {
1220		cl_list_item_t *item = cl_qlist_remove_head(&p_subn->prefix_routes_list);
1221		free(item);
1222	}
1223
1224	subn_opt_destroy(&p_subn->opt);
1225	free(p_subn->opt.file_opts);
1226}
1227
1228ib_api_status_t osm_subn_init(IN osm_subn_t * p_subn, IN osm_opensm_t * p_osm,
1229			      IN const osm_subn_opt_t * p_opt)
1230{
1231	cl_status_t status;
1232
1233	p_subn->p_osm = p_osm;
1234
1235	status = cl_ptr_vector_init(&p_subn->port_lid_tbl,
1236				    OSM_SUBNET_VECTOR_MIN_SIZE,
1237				    OSM_SUBNET_VECTOR_GROW_SIZE);
1238	if (status != CL_SUCCESS)
1239		return status;
1240
1241	status = cl_ptr_vector_set_capacity(&p_subn->port_lid_tbl,
1242					    OSM_SUBNET_VECTOR_CAPACITY);
1243	if (status != CL_SUCCESS)
1244		return status;
1245
1246	/*
1247	   LID zero is not valid.  NULL out this entry for the
1248	   convenience of other code.
1249	 */
1250	cl_ptr_vector_set(&p_subn->port_lid_tbl, 0, NULL);
1251
1252	p_subn->opt = *p_opt;
1253	p_subn->max_ucast_lid_ho = IB_LID_UCAST_END_HO;
1254	p_subn->max_mcast_lid_ho = IB_LID_MCAST_END_HO;
1255	p_subn->min_ca_mtu = IB_MAX_MTU;
1256	p_subn->min_ca_rate = IB_PATH_RECORD_RATE_300_GBS;
1257	p_subn->min_data_vls = IB_MAX_NUM_VLS - 1;
1258	p_subn->min_sw_data_vls = IB_MAX_NUM_VLS - 1;
1259	p_subn->ignore_existing_lfts = TRUE;
1260
1261	/* we assume master by default - so we only need to set it true if STANDBY */
1262	p_subn->coming_out_of_standby = FALSE;
1263	p_subn->sweeping_enabled = TRUE;
1264	p_subn->last_sm_port_state = 1;
1265
1266	/* Initialize the guid2mkey database */
1267	p_subn->p_g2m = osm_db_domain_init(&(p_osm->db), "guid2mkey");
1268	if (!p_subn->p_g2m) {
1269		OSM_LOG(&(p_osm->log), OSM_LOG_ERROR, "ERR 7510: "
1270			"Error initializing Guid-to-MKey persistent database\n");
1271		return IB_ERROR;
1272	}
1273
1274	if (osm_db_restore(p_subn->p_g2m)) {
1275#ifndef __WIN__
1276		/*
1277		 * When Windows is BSODing, it might corrupt files that
1278		 * were previously opened for writing, even if the files
1279		 * are closed, so we might see corrupted guid2mkey file.
1280		 */
1281		if (p_subn->opt.exit_on_fatal) {
1282			osm_log(&(p_osm->log), OSM_LOG_SYS,
1283				"FATAL: Error restoring Guid-to-Mkey "
1284				"persistent database\n");
1285			return IB_ERROR;
1286		} else
1287#endif
1288			OSM_LOG(&(p_osm->log), OSM_LOG_ERROR,
1289				"ERR 7511: Error restoring Guid-to-Mkey "
1290				"persistent database\n");
1291	}
1292
1293	subn_validate_g2m(p_subn);
1294
1295	/* Initialize the neighbor database */
1296	p_subn->p_neighbor = osm_db_domain_init(&(p_osm->db), "neighbors");
1297	if (!p_subn->p_neighbor) {
1298		OSM_LOG(&(p_osm->log), OSM_LOG_ERROR, "ERR 7520: Error "
1299			"initializing neighbor link persistent database\n");
1300		return IB_ERROR;
1301	}
1302
1303	if (osm_db_restore(p_subn->p_neighbor)) {
1304#ifndef __WIN__
1305		/*
1306		 * When Windows is BSODing, it might corrupt files that
1307		 * were previously opened for writing, even if the files
1308		 * are closed, so we might see corrupted neighbors file.
1309		 */
1310		if (p_subn->opt.exit_on_fatal) {
1311			osm_log(&(p_osm->log), OSM_LOG_SYS,
1312				"FATAL: Error restoring neighbor link "
1313				"persistent database\n");
1314			return IB_ERROR;
1315		} else
1316#endif
1317			OSM_LOG(&(p_osm->log), OSM_LOG_ERROR,
1318				"ERR 7521: Error restoring neighbor link "
1319				"persistent database\n");
1320	}
1321
1322	subn_validate_neighbor(p_subn);
1323
1324	return IB_SUCCESS;
1325}
1326
1327osm_port_t *osm_get_port_by_mad_addr(IN osm_log_t * p_log,
1328				     IN const osm_subn_t * p_subn,
1329				     IN osm_mad_addr_t * p_mad_addr)
1330{
1331	osm_port_t *port = osm_get_port_by_lid(p_subn, p_mad_addr->dest_lid);
1332	if (!port)
1333		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7504: "
1334			"Lid is out of range: %u\n",
1335			cl_ntoh16(p_mad_addr->dest_lid));
1336
1337	return port;
1338}
1339
1340ib_api_status_t osm_get_gid_by_mad_addr(IN osm_log_t * p_log,
1341					IN const osm_subn_t * p_subn,
1342					IN osm_mad_addr_t * p_mad_addr,
1343					OUT ib_gid_t * p_gid)
1344{
1345	const osm_port_t *p_port;
1346
1347	if (p_gid == NULL) {
1348		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7505: "
1349			"Provided output GID is NULL\n");
1350		return IB_INVALID_PARAMETER;
1351	}
1352
1353	p_port = osm_get_port_by_mad_addr(p_log, p_subn, p_mad_addr);
1354	if (!p_port)
1355		return IB_INVALID_PARAMETER;
1356
1357	p_gid->unicast.interface_id = p_port->p_physp->port_guid;
1358	p_gid->unicast.prefix = p_subn->opt.subnet_prefix;
1359
1360	return IB_SUCCESS;
1361}
1362
1363osm_physp_t *osm_get_physp_by_mad_addr(IN osm_log_t * p_log,
1364				       IN const osm_subn_t * p_subn,
1365				       IN osm_mad_addr_t * p_mad_addr)
1366{
1367	osm_port_t *p_port;
1368
1369	p_port = osm_get_port_by_mad_addr(p_log, p_subn, p_mad_addr);
1370	if (!p_port)
1371		return NULL;
1372
1373	return p_port->p_physp;
1374}
1375
1376osm_switch_t *osm_get_switch_by_guid(IN const osm_subn_t * p_subn,
1377				     IN ib_net64_t guid)
1378{
1379	osm_switch_t *p_switch;
1380
1381	p_switch = (osm_switch_t *) cl_qmap_get(&(p_subn->sw_guid_tbl), guid);
1382	if (p_switch == (osm_switch_t *) cl_qmap_end(&(p_subn->sw_guid_tbl)))
1383		p_switch = NULL;
1384	return p_switch;
1385}
1386
1387osm_node_t *osm_get_node_by_guid(IN osm_subn_t const *p_subn, IN ib_net64_t guid)
1388{
1389	osm_node_t *p_node;
1390
1391	p_node = (osm_node_t *) cl_qmap_get(&(p_subn->node_guid_tbl), guid);
1392	if (p_node == (osm_node_t *) cl_qmap_end(&(p_subn->node_guid_tbl)))
1393		p_node = NULL;
1394	return p_node;
1395}
1396
1397osm_port_t *osm_get_port_by_guid(IN osm_subn_t const *p_subn, IN ib_net64_t guid)
1398{
1399	osm_port_t *p_port;
1400
1401	p_port = (osm_port_t *) cl_qmap_get(&(p_subn->port_guid_tbl), guid);
1402	if (p_port == (osm_port_t *) cl_qmap_end(&(p_subn->port_guid_tbl)))
1403		p_port = NULL;
1404	return p_port;
1405}
1406
1407osm_alias_guid_t *osm_get_alias_guid_by_guid(IN osm_subn_t const *p_subn,
1408					     IN ib_net64_t guid)
1409{
1410	osm_alias_guid_t *p_alias_guid;
1411
1412	p_alias_guid = (osm_alias_guid_t *) cl_qmap_get(&(p_subn->alias_port_guid_tbl), guid);
1413	if (p_alias_guid == (osm_alias_guid_t *) cl_qmap_end(&(p_subn->alias_port_guid_tbl)))
1414		return NULL;
1415	return p_alias_guid;
1416}
1417
1418osm_port_t *osm_get_port_by_alias_guid(IN osm_subn_t const *p_subn,
1419				       IN ib_net64_t guid)
1420{
1421	osm_alias_guid_t *p_alias_guid;
1422
1423	p_alias_guid = osm_get_alias_guid_by_guid(p_subn, guid);
1424	if (!p_alias_guid)
1425		return NULL;
1426	return p_alias_guid->p_base_port;
1427}
1428
1429osm_assigned_guids_t *osm_assigned_guids_new(IN const ib_net64_t port_guid,
1430					     IN const uint32_t num_guids)
1431{
1432	osm_assigned_guids_t *p_assigned_guids;
1433
1434	p_assigned_guids = calloc(1, sizeof(*p_assigned_guids) +
1435				     sizeof(ib_net64_t) * (num_guids - 1));
1436	if (p_assigned_guids)
1437		p_assigned_guids->port_guid = port_guid;
1438	return p_assigned_guids;
1439}
1440
1441void osm_assigned_guids_delete(IN OUT osm_assigned_guids_t ** pp_assigned_guids)
1442{
1443	free(*pp_assigned_guids);
1444	*pp_assigned_guids = NULL;
1445}
1446
1447osm_assigned_guids_t *osm_get_assigned_guids_by_guid(IN osm_subn_t const *p_subn,
1448						     IN ib_net64_t port_guid)
1449{
1450	osm_assigned_guids_t *p_assigned_guids;
1451
1452	p_assigned_guids = (osm_assigned_guids_t *) cl_qmap_get(&(p_subn->assigned_guids_tbl), port_guid);
1453	if (p_assigned_guids == (osm_assigned_guids_t *) cl_qmap_end(&(p_subn->assigned_guids_tbl)))
1454		return NULL;
1455	return p_assigned_guids;
1456}
1457
1458osm_port_t *osm_get_port_by_lid_ho(IN osm_subn_t const * subn, IN uint16_t lid)
1459{
1460	if (lid < cl_ptr_vector_get_size(&subn->port_lid_tbl))
1461		return cl_ptr_vector_get(&subn->port_lid_tbl, lid);
1462	return NULL;
1463}
1464
1465osm_mgrp_t *osm_get_mgrp_by_mgid(IN osm_subn_t * subn, IN ib_gid_t * mgid)
1466{
1467	osm_mgrp_t *mgrp;
1468
1469	mgrp = (osm_mgrp_t *)cl_fmap_get(&subn->mgrp_mgid_tbl, mgid);
1470	if (mgrp != (osm_mgrp_t *)cl_fmap_end(&subn->mgrp_mgid_tbl))
1471		return mgrp;
1472	return NULL;
1473}
1474
1475int is_mlnx_ext_port_info_supported(ib_net32_t vendid, ib_net16_t devid)
1476{
1477	uint32_t vendid_ho;
1478	uint16_t devid_ho;
1479
1480	devid_ho = cl_ntoh16(devid);
1481	if ((devid_ho >= 0xc738 && devid_ho <= 0xc73b) || devid_ho == 0xcb20 ||
1482	    devid_ho == 0xcf08 || devid == 0x1b02)
1483		return 1;
1484	if (devid_ho >= 0x1003 && devid_ho <= 0x1017)
1485		return 1;
1486
1487	vendid_ho = cl_ntoh32(vendid);
1488	if (vendid_ho == 0x119f) {
1489		/* Bull Switch-X */
1490		if (devid_ho == 0x1b02 || devid_ho == 0x1b50)
1491			return 1;
1492		/* Bull Switch-IB/IB2 */
1493		if (devid_ho == 0x1ba0 ||
1494		    (devid_ho >= 0x1bd0 && devid_ho <= 0x1bd5))
1495			return 1;
1496		/* Bull Connect-X3 */
1497		if (devid_ho == 0x1b33 || devid_ho == 0x1b73 ||
1498		    devid_ho == 0x1b40 || devid_ho == 0x1b41 ||
1499		    devid_ho == 0x1b60 || devid_ho == 0x1b61)
1500			return 1;
1501		/* Bull Connect-IB */
1502		if (devid_ho == 0x1b83 ||
1503		    devid_ho == 0x1b93 || devid_ho == 0x1b94)
1504			return 1;
1505		/* Bull Connect-X4 */
1506		if (devid_ho == 0x1bb4 || devid_ho == 0x1bb5 ||
1507		    devid_ho == 0x1bc4)
1508			return 1;
1509	}
1510	return 0;
1511}
1512
1513static void subn_init_qos_options(osm_qos_options_t *opt, osm_qos_options_t *f)
1514{
1515	opt->max_vls = 0;
1516	opt->high_limit = -1;
1517	if (opt->vlarb_high)
1518		free(opt->vlarb_high);
1519	opt->vlarb_high = NULL;
1520	if (opt->vlarb_low)
1521		free(opt->vlarb_low);
1522	opt->vlarb_low = NULL;
1523	if (opt->sl2vl)
1524		free(opt->sl2vl);
1525	opt->sl2vl = NULL;
1526	if (f)
1527		memcpy(f, opt, sizeof(*f));
1528}
1529
1530void osm_subn_set_default_opt(IN osm_subn_opt_t * p_opt)
1531{
1532	memset(p_opt, 0, sizeof(osm_subn_opt_t));
1533	p_opt->guid = 0;
1534	p_opt->m_key = OSM_DEFAULT_M_KEY;
1535	p_opt->sm_key = OSM_DEFAULT_SM_KEY;
1536	p_opt->sa_key = OSM_DEFAULT_SA_KEY;
1537	p_opt->subnet_prefix = IB_DEFAULT_SUBNET_PREFIX;
1538	p_opt->m_key_lease_period = 0;
1539	p_opt->m_key_protect_bits = 0;
1540	p_opt->m_key_lookup = TRUE;
1541	p_opt->sweep_interval = OSM_DEFAULT_SWEEP_INTERVAL_SECS;
1542	p_opt->max_wire_smps = OSM_DEFAULT_SMP_MAX_ON_WIRE;
1543	p_opt->max_wire_smps2 = p_opt->max_wire_smps;
1544	p_opt->console = strdup(OSM_DEFAULT_CONSOLE);
1545	p_opt->console_port = OSM_DEFAULT_CONSOLE_PORT;
1546	p_opt->transaction_timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC;
1547	p_opt->transaction_retries = OSM_DEFAULT_RETRY_COUNT;
1548	p_opt->max_smps_timeout = 1000 * p_opt->transaction_timeout *
1549				  p_opt->transaction_retries;
1550	/* by default we will consider waiting for 50x transaction timeout normal */
1551	p_opt->max_msg_fifo_timeout = 50 * OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC;
1552	p_opt->sm_priority = OSM_DEFAULT_SM_PRIORITY;
1553	p_opt->lmc = OSM_DEFAULT_LMC;
1554	p_opt->lmc_esp0 = FALSE;
1555	p_opt->max_op_vls = OSM_DEFAULT_MAX_OP_VLS;
1556	p_opt->force_link_speed = 15;
1557	p_opt->force_link_speed_ext = 31;
1558	p_opt->fdr10 = 1;
1559	p_opt->reassign_lids = FALSE;
1560	p_opt->ignore_other_sm = FALSE;
1561	p_opt->single_thread = FALSE;
1562	p_opt->disable_multicast = FALSE;
1563	p_opt->force_log_flush = FALSE;
1564	p_opt->subnet_timeout = OSM_DEFAULT_SUBNET_TIMEOUT;
1565	p_opt->packet_life_time = OSM_DEFAULT_SWITCH_PACKET_LIFE;
1566	p_opt->vl_stall_count = OSM_DEFAULT_VL_STALL_COUNT;
1567	p_opt->leaf_vl_stall_count = OSM_DEFAULT_LEAF_VL_STALL_COUNT;
1568	p_opt->head_of_queue_lifetime = OSM_DEFAULT_HEAD_OF_QUEUE_LIFE;
1569	p_opt->leaf_head_of_queue_lifetime =
1570	    OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE;
1571	p_opt->local_phy_errors_threshold = OSM_DEFAULT_ERROR_THRESHOLD;
1572	p_opt->overrun_errors_threshold = OSM_DEFAULT_ERROR_THRESHOLD;
1573	p_opt->use_mfttop = TRUE;
1574	p_opt->sminfo_polling_timeout =
1575	    OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS;
1576	p_opt->polling_retry_number = OSM_SM_DEFAULT_POLLING_RETRY_NUMBER;
1577	p_opt->force_heavy_sweep = FALSE;
1578	p_opt->log_flags = OSM_LOG_DEFAULT_LEVEL;
1579	p_opt->honor_guid2lid_file = FALSE;
1580	p_opt->daemon = FALSE;
1581	p_opt->sm_inactive = FALSE;
1582	p_opt->babbling_port_policy = FALSE;
1583	p_opt->drop_event_subscriptions = FALSE;
1584	p_opt->ipoib_mcgroup_creation_validation = TRUE;
1585	p_opt->mcgroup_join_validation = TRUE;
1586	p_opt->use_optimized_slvl = FALSE;
1587	p_opt->fsync_high_avail_files = TRUE;
1588#ifdef ENABLE_OSM_PERF_MGR
1589	p_opt->perfmgr = FALSE;
1590	p_opt->perfmgr_redir = TRUE;
1591	p_opt->perfmgr_sweep_time_s = OSM_PERFMGR_DEFAULT_SWEEP_TIME_S;
1592	p_opt->perfmgr_max_outstanding_queries =
1593	    OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES;
1594	p_opt->perfmgr_ignore_cas = FALSE;
1595	p_opt->event_db_dump_file = NULL; /* use default */
1596	p_opt->perfmgr_rm_nodes = TRUE;
1597	p_opt->perfmgr_log_errors = TRUE;
1598	p_opt->perfmgr_query_cpi = TRUE;
1599	p_opt->perfmgr_xmit_wait_log = FALSE;
1600	p_opt->perfmgr_xmit_wait_threshold = OSM_PERFMGR_DEFAULT_XMIT_WAIT_THRESHOLD;
1601#endif				/* ENABLE_OSM_PERF_MGR */
1602
1603	p_opt->event_plugin_name = NULL;
1604	p_opt->event_plugin_options = NULL;
1605	p_opt->node_name_map_name = NULL;
1606
1607	p_opt->dump_files_dir = getenv("OSM_TMP_DIR");
1608	if (!p_opt->dump_files_dir || !(*p_opt->dump_files_dir))
1609		p_opt->dump_files_dir = strdup(OSM_DEFAULT_TMP_DIR);
1610	else
1611		p_opt->dump_files_dir = strdup(p_opt->dump_files_dir);
1612	p_opt->log_file = strdup(OSM_DEFAULT_LOG_FILE);
1613	p_opt->log_max_size = 0;
1614	p_opt->partition_config_file = strdup(OSM_DEFAULT_PARTITION_CONFIG_FILE);
1615	p_opt->no_partition_enforcement = FALSE;
1616	p_opt->part_enforce = strdup(OSM_PARTITION_ENFORCE_BOTH);
1617	p_opt->allow_both_pkeys = FALSE;
1618	p_opt->sm_assigned_guid = 0;
1619	p_opt->qos = FALSE;
1620	p_opt->qos_policy_file = strdup(OSM_DEFAULT_QOS_POLICY_FILE);
1621	p_opt->suppress_sl2vl_mad_status_errors = FALSE;
1622	p_opt->accum_log_file = TRUE;
1623	p_opt->port_prof_ignore_file = NULL;
1624	p_opt->hop_weights_file = NULL;
1625	p_opt->port_search_ordering_file = NULL;
1626	p_opt->port_profile_switch_nodes = FALSE;
1627	p_opt->sweep_on_trap = TRUE;
1628	p_opt->use_ucast_cache = FALSE;
1629	p_opt->routing_engine_names = NULL;
1630	p_opt->connect_roots = FALSE;
1631	p_opt->lid_matrix_dump_file = NULL;
1632	p_opt->lfts_file = NULL;
1633	p_opt->root_guid_file = NULL;
1634	p_opt->cn_guid_file = NULL;
1635	p_opt->io_guid_file = NULL;
1636	p_opt->port_shifting = FALSE;
1637	p_opt->scatter_ports = OSM_DEFAULT_SCATTER_PORTS;
1638	p_opt->max_reverse_hops = 0;
1639	p_opt->ids_guid_file = NULL;
1640	p_opt->guid_routing_order_file = NULL;
1641	p_opt->guid_routing_order_no_scatter = FALSE;
1642	p_opt->sa_db_file = NULL;
1643	p_opt->sa_db_dump = FALSE;
1644	p_opt->torus_conf_file = strdup(OSM_DEFAULT_TORUS_CONF_FILE);
1645	p_opt->do_mesh_analysis = FALSE;
1646	p_opt->exit_on_fatal = TRUE;
1647	p_opt->congestion_control = FALSE;
1648	p_opt->cc_key = OSM_DEFAULT_CC_KEY;
1649	p_opt->cc_max_outstanding_mads = OSM_CC_DEFAULT_MAX_OUTSTANDING_QUERIES;
1650	p_opt->enable_quirks = FALSE;
1651	p_opt->no_clients_rereg = FALSE;
1652	p_opt->prefix_routes_file = strdup(OSM_DEFAULT_PREFIX_ROUTES_FILE);
1653	p_opt->consolidate_ipv6_snm_req = FALSE;
1654	p_opt->lash_start_vl = 0;
1655	p_opt->sm_sl = OSM_DEFAULT_SL;
1656	p_opt->log_prefix = NULL;
1657	p_opt->per_module_logging_file = strdup(OSM_DEFAULT_PER_MOD_LOGGING_CONF_FILE);
1658	subn_init_qos_options(&p_opt->qos_options, NULL);
1659	subn_init_qos_options(&p_opt->qos_ca_options, NULL);
1660	subn_init_qos_options(&p_opt->qos_sw0_options, NULL);
1661	subn_init_qos_options(&p_opt->qos_swe_options, NULL);
1662	subn_init_qos_options(&p_opt->qos_rtr_options, NULL);
1663	p_opt->cc_cct.entries_len = 0;
1664	p_opt->cc_cct.input_str = NULL;
1665	p_opt->quasi_ftree_indexing = FALSE;
1666}
1667
1668static char *clean_val(char *val)
1669{
1670	char *p = val;
1671	/* clean leading spaces */
1672	while (isspace(*p))
1673		p++;
1674	val = p;
1675	if (!*val)
1676		return val;
1677	/* clean trailing spaces */
1678	p = val + strlen(val) - 1;
1679	while (p > val && isspace(*p))
1680		p--;
1681	p[1] = '\0';
1682	/* clean quotas */
1683	if ((*val == '\"' && *p == '\"') || (*val == '\'' && *p == '\'')) {
1684		val++;
1685		*p-- = '\0';
1686	}
1687	return val;
1688}
1689
1690static int subn_dump_qos_options(FILE * file, const char *set_name,
1691				 const char *prefix, osm_qos_options_t * opt)
1692{
1693	return fprintf(file, "# %s\n"
1694		       "%s_max_vls %u\n"
1695		       "%s_high_limit %d\n"
1696		       "%s_vlarb_high %s\n"
1697		       "%s_vlarb_low %s\n"
1698		       "%s_sl2vl %s\n",
1699		       set_name,
1700		       prefix, opt->max_vls,
1701		       prefix, opt->high_limit,
1702		       prefix, opt->vlarb_high,
1703		       prefix, opt->vlarb_low, prefix, opt->sl2vl);
1704}
1705
1706static ib_api_status_t append_prefix_route(IN osm_subn_t * p_subn,
1707					   uint64_t prefix, uint64_t guid)
1708{
1709	osm_prefix_route_t *route;
1710
1711	route = malloc(sizeof *route);
1712	if (! route) {
1713		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "out of memory");
1714		return IB_ERROR;
1715	}
1716
1717	route->prefix = cl_hton64(prefix);
1718	route->guid = cl_hton64(guid);
1719	cl_qlist_insert_tail(&p_subn->prefix_routes_list, &route->list_item);
1720	return IB_SUCCESS;
1721}
1722
1723static ib_api_status_t parse_prefix_routes_file(IN osm_subn_t * p_subn)
1724{
1725	osm_log_t *log = &p_subn->p_osm->log;
1726	FILE *fp;
1727	char buf[1024];
1728	int line = 0;
1729	int errors = 0;
1730
1731	while (!cl_is_qlist_empty(&p_subn->prefix_routes_list)) {
1732		cl_list_item_t *item = cl_qlist_remove_head(&p_subn->prefix_routes_list);
1733		free(item);
1734	}
1735
1736	fp = fopen(p_subn->opt.prefix_routes_file, "r");
1737	if (! fp) {
1738		if (errno == ENOENT)
1739			return IB_SUCCESS;
1740
1741		OSM_LOG(log, OSM_LOG_ERROR, "fopen(%s) failed: %s",
1742			p_subn->opt.prefix_routes_file, strerror(errno));
1743		return IB_ERROR;
1744	}
1745
1746	while (fgets(buf, sizeof buf, fp) != NULL) {
1747		char *p_prefix, *p_guid, *p_extra, *p_last, *p_end;
1748		uint64_t prefix, guid;
1749
1750		line++;
1751		if (errors > 10)
1752			break;
1753
1754		p_prefix = strtok_r(buf, " \t\n", &p_last);
1755		if (! p_prefix)
1756			continue; /* ignore blank lines */
1757
1758		if (*p_prefix == '#')
1759			continue; /* ignore comment lines */
1760
1761		p_guid = strtok_r(NULL, " \t\n", &p_last);
1762		if (! p_guid) {
1763			OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: missing GUID\n",
1764				p_subn->opt.prefix_routes_file, line);
1765			errors++;
1766			continue;
1767		}
1768
1769		p_extra = strtok_r(NULL, " \t\n", &p_last);
1770		if (p_extra && *p_extra != '#') {
1771			OSM_LOG(log, OSM_LOG_INFO, "%s:%d: extra tokens ignored\n",
1772				p_subn->opt.prefix_routes_file, line);
1773		}
1774
1775		if (strcmp(p_prefix, "*") == 0)
1776			prefix = 0;
1777		else {
1778			prefix = strtoull(p_prefix, &p_end, 16);
1779			if (*p_end != '\0') {
1780				OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: illegal prefix: %s\n",
1781					p_subn->opt.prefix_routes_file, line, p_prefix);
1782				errors++;
1783				continue;
1784			}
1785		}
1786
1787		if (strcmp(p_guid, "*") == 0)
1788			guid = 0;
1789		else {
1790			guid = strtoull(p_guid, &p_end, 16);
1791			if (*p_end != '\0' && *p_end != '#') {
1792				OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: illegal GUID: %s\n",
1793					p_subn->opt.prefix_routes_file, line, p_guid);
1794				errors++;
1795				continue;
1796			}
1797		}
1798
1799		if (append_prefix_route(p_subn, prefix, guid) != IB_SUCCESS) {
1800			errors++;
1801			break;
1802		}
1803	}
1804
1805	fclose(fp);
1806	return (errors == 0) ? IB_SUCCESS : IB_ERROR;
1807}
1808
1809static ib_api_status_t insert_per_module_debug(IN osm_subn_t * p_subn,
1810					       char *mod_name,
1811					       osm_log_level_t level)
1812{
1813	uint8_t index;
1814
1815	if (find_module_name(mod_name, &index)) {
1816		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR,
1817			"Module name %s not found\n", mod_name);
1818		return IB_ERROR;
1819	}
1820	osm_set_log_per_module(&p_subn->p_osm->log, index, level);
1821	return IB_SUCCESS;
1822}
1823
1824static ib_api_status_t parse_per_mod_logging_file(IN osm_subn_t * p_subn)
1825{
1826	osm_log_t *log = &p_subn->p_osm->log;
1827	FILE *fp;
1828	char buf[1024];
1829	int line = 0;
1830	int errors = 0;
1831
1832	osm_reset_log_per_module(log);
1833
1834	if (p_subn->opt.per_module_logging_file == NULL)
1835		return IB_SUCCESS;
1836
1837	fp = fopen(p_subn->opt.per_module_logging_file, "r");
1838	if (!fp) {
1839		if (errno == ENOENT)
1840			return IB_SUCCESS;
1841
1842		OSM_LOG(log, OSM_LOG_ERROR, "fopen(%s) failed: %s",
1843			p_subn->opt.per_module_logging_file, strerror(errno));
1844		return IB_ERROR;
1845	}
1846
1847	while (fgets(buf, sizeof buf, fp) != NULL) {
1848		char *p_mod_name, *p_level, *p_extra, *p_last;
1849		osm_log_level_t level;
1850
1851		line++;
1852		if (errors > 10)
1853			break;
1854
1855		p_mod_name = strtok_r(buf, " =,\t\n", &p_last);
1856		if (!p_mod_name)
1857			continue; /* ignore blank lines */
1858
1859		if (*p_mod_name == '#')
1860			continue; /* ignore comment lines */
1861
1862		p_level = strtok_r(NULL, " \t\n", &p_last);
1863		if (!p_level) {
1864			OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: missing log level\n",
1865				p_subn->opt.per_module_logging_file, line);
1866			errors++;
1867			continue;
1868		}
1869		p_extra = strtok_r(NULL, " \t\n", &p_last);
1870		if (p_extra && *p_extra != '#') {
1871			OSM_LOG(log, OSM_LOG_INFO, "%s:%d: extra tokens ignored\n",
1872				p_subn->opt.per_module_logging_file, line);
1873		}
1874
1875		level = strtoul(p_level, NULL, 0);
1876		if (insert_per_module_debug(p_subn, p_mod_name, level) != IB_SUCCESS) {
1877			errors++;
1878			break;
1879		}
1880	}
1881
1882	fclose(fp);
1883	return (errors == 0) ? IB_SUCCESS : IB_ERROR;
1884}
1885
1886static void subn_verify_max_vls(unsigned *max_vls, const char *prefix)
1887{
1888	if (!*max_vls || *max_vls > 15) {
1889		if (*max_vls)
1890			log_report(" Invalid Cached Option: %s_max_vls=%u: "
1891				   "Using Default = %u\n",
1892				   prefix, *max_vls, OSM_DEFAULT_QOS_MAX_VLS);
1893		*max_vls = 0;
1894	}
1895}
1896
1897static void subn_verify_high_limit(int *high_limit, const char *prefix)
1898{
1899	if (*high_limit < 0 || *high_limit > 255) {
1900		if (*high_limit > 255)
1901			log_report(" Invalid Cached Option: %s_high_limit=%d: "
1902				   "Using Default: %d\n",
1903				   prefix, *high_limit,
1904				   OSM_DEFAULT_QOS_HIGH_LIMIT);
1905		*high_limit = -1;
1906	}
1907}
1908
1909static void subn_verify_vlarb(char **vlarb, const char *prefix,
1910			      const char *suffix)
1911{
1912	char *str, *tok, *end, *ptr;
1913	int count = 0;
1914
1915	if (*vlarb == NULL)
1916		return;
1917
1918	str = strdup(*vlarb);
1919
1920	tok = strtok_r(str, ",\n", &ptr);
1921	while (tok) {
1922		char *vl_str, *weight_str;
1923
1924		vl_str = tok;
1925		weight_str = strchr(tok, ':');
1926
1927		if (weight_str) {
1928			long vl, weight;
1929
1930			*weight_str = '\0';
1931			weight_str++;
1932
1933			vl = strtol(vl_str, &end, 0);
1934
1935			if (*end)
1936				log_report(" Warning: Cached Option "
1937					   "%s_vlarb_%s:vl=%s"
1938					   " improperly formatted\n",
1939					   prefix, suffix, vl_str);
1940			else if (vl < 0 || vl > 14)
1941				log_report(" Warning: Cached Option "
1942					   "%s_vlarb_%s:vl=%ld out of range\n",
1943					   prefix, suffix, vl);
1944
1945			weight = strtol(weight_str, &end, 0);
1946
1947			if (*end)
1948				log_report(" Warning: Cached Option "
1949					   "%s_vlarb_%s:weight=%s "
1950					   "improperly formatted\n",
1951					   prefix, suffix, weight_str);
1952			else if (weight < 0 || weight > 255)
1953				log_report(" Warning: Cached Option "
1954					   "%s_vlarb_%s:weight=%ld "
1955					   "out of range\n",
1956					   prefix, suffix, weight);
1957		} else
1958			log_report(" Warning: Cached Option "
1959				   "%s_vlarb_%s:vl:weight=%s "
1960				   "improperly formatted\n",
1961				   prefix, suffix, tok);
1962
1963		count++;
1964		tok = strtok_r(NULL, ",\n", &ptr);
1965	}
1966
1967	if (count > 64)
1968		log_report(" Warning: Cached Option %s_vlarb_%s: > 64 listed:"
1969			   " excess vl:weight pairs will be dropped\n",
1970			   prefix, suffix);
1971
1972	free(str);
1973}
1974
1975static void subn_verify_sl2vl(char **sl2vl, const char *prefix)
1976{
1977	char *str, *tok, *end, *ptr;
1978	int count = 0;
1979
1980	if (*sl2vl == NULL)
1981		return;
1982
1983	str = strdup(*sl2vl);
1984
1985	tok = strtok_r(str, ",\n", &ptr);
1986	while (tok) {
1987		long vl = strtol(tok, &end, 0);
1988
1989		if (*end)
1990			log_report(" Warning: Cached Option %s_sl2vl:vl=%s "
1991				   "improperly formatted\n", prefix, tok);
1992		else if (vl < 0 || vl > 15)
1993			log_report(" Warning: Cached Option %s_sl2vl:vl=%ld "
1994				   "out of range\n", prefix, vl);
1995
1996		count++;
1997		tok = strtok_r(NULL, ",\n", &ptr);
1998	}
1999
2000	if (count < 16)
2001		log_report(" Warning: Cached Option %s_sl2vl: < 16 VLs "
2002			   "listed\n", prefix);
2003	else if (count > 16)
2004		log_report(" Warning: Cached Option %s_sl2vl: > 16 listed: "
2005			   "excess VLs will be dropped\n", prefix);
2006
2007	free(str);
2008}
2009
2010static void subn_verify_qos_set(osm_qos_options_t *set, const char *prefix)
2011{
2012	subn_verify_max_vls(&set->max_vls, prefix);
2013	subn_verify_high_limit(&set->high_limit, prefix);
2014	subn_verify_vlarb(&set->vlarb_low, prefix, "low");
2015	subn_verify_vlarb(&set->vlarb_high, prefix, "high");
2016	subn_verify_sl2vl(&set->sl2vl, prefix);
2017}
2018
2019int osm_subn_verify_config(IN osm_subn_opt_t * p_opts)
2020{
2021	if (p_opts->lmc > 7) {
2022		log_report(" Invalid Cached Option Value:lmc = %u:"
2023			   "Using Default:%u\n", p_opts->lmc, OSM_DEFAULT_LMC);
2024		p_opts->lmc = OSM_DEFAULT_LMC;
2025	}
2026
2027	if (15 < p_opts->sm_priority) {
2028		log_report(" Invalid Cached Option Value:sm_priority = %u:"
2029			   "Using Default:%u\n",
2030			   p_opts->sm_priority, OSM_DEFAULT_SM_PRIORITY);
2031		p_opts->sm_priority = OSM_DEFAULT_SM_PRIORITY;
2032	}
2033
2034	if ((15 < p_opts->force_link_speed) ||
2035	    (p_opts->force_link_speed > 7 && p_opts->force_link_speed < 15)) {
2036		log_report(" Invalid Cached Option Value:force_link_speed = %u:"
2037			   "Using Default:%u\n", p_opts->force_link_speed,
2038			   IB_PORT_LINK_SPEED_ENABLED_MASK);
2039		p_opts->force_link_speed = IB_PORT_LINK_SPEED_ENABLED_MASK;
2040	}
2041
2042	if ((31 < p_opts->force_link_speed_ext) ||
2043	    (p_opts->force_link_speed_ext > 3 && p_opts->force_link_speed_ext < 30)) {
2044		log_report(" Invalid Cached Option Value:force_link_speed_ext = %u:"
2045			   "Using Default:%u\n", p_opts->force_link_speed_ext,
2046			   31);
2047		p_opts->force_link_speed_ext = 31;
2048	}
2049
2050	if (2 < p_opts->fdr10) {
2051		log_report(" Invalid Cached Option Value:fdr10 = %u:"
2052			   "Using Default:%u\n", p_opts->fdr10, 1);
2053		p_opts->fdr10 = 1;
2054	}
2055
2056	if (p_opts->max_wire_smps == 0)
2057		p_opts->max_wire_smps = 0x7FFFFFFF;
2058	else if (p_opts->max_wire_smps > 0x7FFFFFFF) {
2059		log_report(" Invalid Cached Option Value: max_wire_smps = %u,"
2060			   " Using Default: %u\n",
2061			   p_opts->max_wire_smps, OSM_DEFAULT_SMP_MAX_ON_WIRE);
2062		p_opts->max_wire_smps = OSM_DEFAULT_SMP_MAX_ON_WIRE;
2063	}
2064
2065	if (p_opts->max_wire_smps2 > 0x7FFFFFFF) {
2066		log_report(" Invalid Cached Option Value: max_wire_smps2 = %u,"
2067			   " Using Default: %u",
2068			   p_opts->max_wire_smps2, p_opts->max_wire_smps);
2069		p_opts->max_wire_smps2 = p_opts->max_wire_smps;
2070	}
2071
2072	if (strcmp(p_opts->console, OSM_DISABLE_CONSOLE)
2073	    && strcmp(p_opts->console, OSM_LOCAL_CONSOLE)
2074#ifdef ENABLE_OSM_CONSOLE_LOOPBACK
2075	    && strcmp(p_opts->console, OSM_LOOPBACK_CONSOLE)
2076#endif
2077#ifdef ENABLE_OSM_CONSOLE_SOCKET
2078	    && strcmp(p_opts->console, OSM_REMOTE_CONSOLE)
2079#endif
2080	    ) {
2081		log_report(" Invalid Cached Option Value:console = %s"
2082			   ", Using Default:%s\n",
2083			   p_opts->console, OSM_DEFAULT_CONSOLE);
2084		free(p_opts->console);
2085		p_opts->console = strdup(OSM_DEFAULT_CONSOLE);
2086	}
2087
2088	if (p_opts->no_partition_enforcement == TRUE) {
2089		strcpy(p_opts->part_enforce, OSM_PARTITION_ENFORCE_OFF);
2090		p_opts->part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_OFF;
2091	} else {
2092		if (strcmp(p_opts->part_enforce, OSM_PARTITION_ENFORCE_BOTH) == 0)
2093			p_opts->part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_BOTH;
2094		else if (strcmp(p_opts->part_enforce, OSM_PARTITION_ENFORCE_IN) == 0)
2095			p_opts->part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_IN;
2096		else if (strcmp(p_opts->part_enforce, OSM_PARTITION_ENFORCE_OUT) == 0)
2097			p_opts->part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_OUT;
2098		else if (strcmp(p_opts->part_enforce, OSM_PARTITION_ENFORCE_OFF) == 0)
2099			p_opts->part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_OFF;
2100		else {
2101			log_report(" Invalid Cached Option Value:part_enforce = %s"
2102	                           ", Using Default:%s\n",
2103	                           p_opts->part_enforce, OSM_PARTITION_ENFORCE_BOTH);
2104			strcpy(p_opts->part_enforce, OSM_PARTITION_ENFORCE_BOTH);
2105			p_opts->part_enforce_enum = OSM_PARTITION_ENFORCE_TYPE_BOTH;
2106		}
2107	}
2108
2109	if (p_opts->qos) {
2110		subn_verify_qos_set(&p_opts->qos_options, "qos");
2111		subn_verify_qos_set(&p_opts->qos_ca_options, "qos_ca");
2112		subn_verify_qos_set(&p_opts->qos_sw0_options, "qos_sw0");
2113		subn_verify_qos_set(&p_opts->qos_swe_options, "qos_swe");
2114		subn_verify_qos_set(&p_opts->qos_rtr_options, "qos_rtr");
2115	}
2116
2117#ifdef ENABLE_OSM_PERF_MGR
2118	if (p_opts->perfmgr_sweep_time_s < 1) {
2119		log_report(" Invalid Cached Option Value:perfmgr_sweep_time_s "
2120			   "= %u Using Default:%u\n",
2121			   p_opts->perfmgr_sweep_time_s,
2122			   OSM_PERFMGR_DEFAULT_SWEEP_TIME_S);
2123		p_opts->perfmgr_sweep_time_s = OSM_PERFMGR_DEFAULT_SWEEP_TIME_S;
2124	}
2125	if (p_opts->perfmgr_max_outstanding_queries < 1) {
2126		log_report(" Invalid Cached Option Value:"
2127			   "perfmgr_max_outstanding_queries = %u"
2128			   " Using Default:%u\n",
2129			   p_opts->perfmgr_max_outstanding_queries,
2130			   OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES);
2131		p_opts->perfmgr_max_outstanding_queries =
2132		    OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES;
2133	}
2134#endif
2135
2136	if (p_opts->m_key_protect_bits > 3) {
2137		log_report(" Invalid Cached Option Value:"
2138			   "m_key_protection_level = %u Setting to %u "
2139			   "instead\n", p_opts->m_key_protect_bits, 2);
2140		p_opts->m_key_protect_bits = 2;
2141	}
2142	if (p_opts->m_key_protect_bits && p_opts->m_key_lease_period) {
2143		if (!p_opts->sweep_interval) {
2144			log_report(" Sweep disabled with protected mkey "
2145				   "leases in effect; re-enabling sweeping "
2146				   "with interval %u\n",
2147				   cl_ntoh16(p_opts->m_key_lease_period) - 1);
2148			p_opts->sweep_interval =
2149				cl_ntoh16(p_opts->m_key_lease_period) - 1;
2150		}
2151		if (p_opts->sweep_interval >=
2152			cl_ntoh16(p_opts->m_key_lease_period)) {
2153			log_report(" Sweep interval %u >= mkey lease period "
2154				   "%u. Setting lease period to %u\n",
2155				   p_opts->sweep_interval,
2156				   cl_ntoh16(p_opts->m_key_lease_period),
2157				   p_opts->sweep_interval + 1);
2158			p_opts->m_key_lease_period =
2159				cl_hton16(p_opts->sweep_interval + 1);
2160		}
2161	}
2162
2163	return 0;
2164}
2165
2166int osm_subn_parse_conf_file(const char *file_name, osm_subn_opt_t * p_opts)
2167{
2168	char line[1024];
2169	FILE *opts_file;
2170	char *p_key, *p_val, *pound_sign;
2171	const opt_rec_t *r;
2172	void *p_field1, *p_field2;
2173	int token_matched;
2174
2175	opts_file = fopen(file_name, "r");
2176	if (!opts_file) {
2177		if (errno == ENOENT)
2178			return 1;
2179		printf("cannot open file \'%s\': %s\n",
2180		       file_name, strerror(errno));
2181		return -1;
2182	}
2183
2184	printf(" Reading Cached Option File: %s\n", file_name);
2185
2186	p_opts->config_file = file_name;
2187	if (!p_opts->file_opts && !(p_opts->file_opts = malloc(sizeof(*p_opts)))) {
2188		fclose(opts_file);
2189		return -1;
2190	}
2191	memcpy(p_opts->file_opts, p_opts, sizeof(*p_opts));
2192	p_opts->file_opts->file_opts = NULL;
2193
2194	while (fgets(line, 1023, opts_file) != NULL) {
2195		pound_sign = strchr(line,'#');
2196		token_matched = 0;
2197		/* Truncate any comments. */
2198		if (pound_sign)
2199			*pound_sign = '\0';
2200
2201		/* get the first token */
2202		p_key = strtok_r(line, " \t\n", &p_val);
2203		if (!p_key)
2204			continue;
2205
2206		p_val = clean_val(p_val);
2207
2208		for (r = opt_tbl; r->name; r++) {
2209			if (strcmp(r->name, p_key))
2210				continue;
2211
2212			token_matched = 1;
2213			p_field1 = (void *)p_opts->file_opts + r->opt_offset;
2214			p_field2 = (void *)p_opts + r->opt_offset;
2215			/* don't call setup function first time */
2216			r->parse_fn(NULL, p_key, p_val, p_field1, p_field2,
2217				    NULL);
2218			break;
2219		}
2220
2221		if (!token_matched)
2222			log_report(" Unrecognized token: \"%s\"\n", p_key);
2223	}
2224	fclose(opts_file);
2225
2226	osm_subn_verify_config(p_opts);
2227
2228	return 0;
2229}
2230
2231int osm_subn_rescan_conf_files(IN osm_subn_t * p_subn)
2232{
2233	char line[1024];
2234	osm_subn_opt_t *p_opts = &p_subn->opt;
2235	const opt_rec_t *r;
2236	FILE *opts_file;
2237	char *p_key, *p_val, *pound_sign;
2238	void *p_field1, *p_field2;
2239	int token_matched;
2240
2241	if (!p_opts->config_file)
2242		return 0;
2243
2244	opts_file = fopen(p_opts->config_file, "r");
2245	if (!opts_file) {
2246		if (errno == ENOENT)
2247			return 1;
2248		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR,
2249			"cannot open file \'%s\': %s\n",
2250			p_opts->config_file, strerror(errno));
2251		return -1;
2252	}
2253
2254	subn_init_qos_options(&p_opts->qos_options,
2255			      &p_opts->file_opts->qos_options);
2256	subn_init_qos_options(&p_opts->qos_ca_options,
2257			      &p_opts->file_opts->qos_ca_options);
2258	subn_init_qos_options(&p_opts->qos_sw0_options,
2259			      &p_opts->file_opts->qos_sw0_options);
2260	subn_init_qos_options(&p_opts->qos_swe_options,
2261			      &p_opts->file_opts->qos_swe_options);
2262	subn_init_qos_options(&p_opts->qos_rtr_options,
2263			      &p_opts->file_opts->qos_rtr_options);
2264
2265	while (fgets(line, 1023, opts_file) != NULL) {
2266		pound_sign = strchr(line,'#');
2267		token_matched = 0;
2268
2269		/* Truncate any comments. */
2270		if (pound_sign)
2271			*pound_sign = '\0';
2272
2273		/* get the first token */
2274		p_key = strtok_r(line, " \t\n", &p_val);
2275		if (!p_key)
2276			continue;
2277
2278		p_val = clean_val(p_val);
2279
2280		for (r = opt_tbl; r->name; r++) {
2281			if (strcmp(r->name, p_key))
2282				continue;
2283
2284			token_matched = 1;
2285
2286			if (!r->can_update)
2287				continue;
2288
2289			p_field1 = (void *)p_opts->file_opts + r->opt_offset;
2290			p_field2 = (void *)p_opts + r->opt_offset;
2291			r->parse_fn(p_subn, p_key, p_val, p_field1, p_field2,
2292				    r->setup_fn);
2293			break;
2294		}
2295		if (!token_matched)
2296                       log_report(" Unrecognized token: \"%s\"\n", p_key);
2297	}
2298	fclose(opts_file);
2299
2300	osm_subn_verify_config(p_opts);
2301
2302	parse_prefix_routes_file(p_subn);
2303
2304	parse_per_mod_logging_file(p_subn);
2305
2306	return 0;
2307}
2308
2309void osm_subn_output_conf(FILE *out, IN osm_subn_opt_t * p_opts)
2310{
2311	int cacongoutputcount = 0;
2312	int i;
2313
2314	fprintf(out,
2315		"#\n# DEVICE ATTRIBUTES OPTIONS\n#\n"
2316		"# The port GUID on which the OpenSM is running\n"
2317		"guid 0x%016" PRIx64 "\n\n"
2318		"# M_Key value sent to all ports qualifying all Set(PortInfo)\n"
2319		"m_key 0x%016" PRIx64 "\n\n"
2320		"# The lease period used for the M_Key on this subnet in [sec]\n"
2321		"m_key_lease_period %u\n\n"
2322		"# The protection level used for the M_Key on this subnet\n"
2323		"m_key_protection_level %u\n\n"
2324		"# If TRUE, SM tries to determine the m_key of unknown ports from guid2mkey file\n"
2325		"# If FALSE, SM won't try to determine the m_key of unknown ports.\n"
2326		"# Preconfigured m_key will be used instead\n"
2327		"m_key_lookup %s\n\n"
2328		"# SM_Key value of the SM used for SM authentication\n"
2329		"sm_key 0x%016" PRIx64 "\n\n"
2330		"# SM_Key value to qualify rcv SA queries as 'trusted'\n"
2331		"sa_key 0x%016" PRIx64 "\n\n"
2332		"# Note that for both values above (sm_key and sa_key)\n"
2333		"# OpenSM version 3.2.1 and below used the default value '1'\n"
2334		"# in a host byte order, it is fixed now but you may need to\n"
2335		"# change the values to interoperate with old OpenSM running\n"
2336		"# on a little endian machine.\n\n"
2337		"# Subnet prefix used on this subnet\n"
2338		"subnet_prefix 0x%016" PRIx64 "\n\n"
2339		"# The LMC value used on this subnet\n"
2340		"lmc %u\n\n"
2341		"# lmc_esp0 determines whether LMC value used on subnet is used for\n"
2342		"# enhanced switch port 0. If TRUE, LMC value for subnet is used for\n"
2343		"# ESP0. Otherwise, LMC value for ESP0s is 0.\n"
2344		"lmc_esp0 %s\n\n"
2345		"# sm_sl determines SMSL used for SM/SA communication\n"
2346		"sm_sl %u\n\n"
2347		"# The code of maximal time a packet can live in a switch\n"
2348		"# The actual time is 4.096usec * 2^<packet_life_time>\n"
2349		"# The value 0x14 disables this mechanism\n"
2350		"packet_life_time 0x%02x\n\n"
2351		"# The number of sequential packets dropped that cause the port\n"
2352		"# to enter the VLStalled state. The result of setting this value to\n"
2353		"# zero is undefined.\n"
2354		"vl_stall_count 0x%02x\n\n"
2355		"# The number of sequential packets dropped that cause the port\n"
2356		"# to enter the VLStalled state. This value is for switch ports\n"
2357		"# driving a CA or router port. The result of setting this value\n"
2358		"# to zero is undefined.\n"
2359		"leaf_vl_stall_count 0x%02x\n\n"
2360		"# The code of maximal time a packet can wait at the head of\n"
2361		"# transmission queue.\n"
2362		"# The actual time is 4.096usec * 2^<head_of_queue_lifetime>\n"
2363		"# The value 0x14 disables this mechanism\n"
2364		"head_of_queue_lifetime 0x%02x\n\n"
2365		"# The maximal time a packet can wait at the head of queue on\n"
2366		"# switch port connected to a CA or router port\n"
2367		"leaf_head_of_queue_lifetime 0x%02x\n\n"
2368		"# Limit the maximal operational VLs\n"
2369		"max_op_vls %u\n\n"
2370		"# Force PortInfo:LinkSpeedEnabled on switch ports\n"
2371		"# If 0, don't modify PortInfo:LinkSpeedEnabled on switch port\n"
2372		"# Otherwise, use value for PortInfo:LinkSpeedEnabled on switch port\n"
2373		"# Values are (IB Spec 1.2.1, 14.2.5.6 Table 146 \"PortInfo\")\n"
2374		"#    1: 2.5 Gbps\n"
2375		"#    3: 2.5 or 5.0 Gbps\n"
2376		"#    5: 2.5 or 10.0 Gbps\n"
2377		"#    7: 2.5 or 5.0 or 10.0 Gbps\n"
2378		"#    2,4,6,8-14 Reserved\n"
2379		"#    Default 15: set to PortInfo:LinkSpeedSupported\n"
2380		"force_link_speed %u\n\n"
2381		"# Force PortInfo:LinkSpeedExtEnabled on ports\n"
2382		"# If 0, don't modify PortInfo:LinkSpeedExtEnabled on port\n"
2383		"# Otherwise, use value for PortInfo:LinkSpeedExtEnabled on port\n"
2384		"# Values are (MgtWG RefID #4722)\n"
2385		"#    1: 14.0625 Gbps\n"
2386		"#    2: 25.78125 Gbps\n"
2387		"#    3: 14.0625 Gbps or 25.78125 Gbps\n"
2388		"#    30: Disable extended link speeds\n"
2389		"#    Default 31: set to PortInfo:LinkSpeedExtSupported\n"
2390		"force_link_speed_ext %u\n\n"
2391		"# FDR10 on ports on devices that support FDR10\n"
2392		"# Values are:\n"
2393		"#    0: don't use fdr10 (no MLNX ExtendedPortInfo MADs)\n"
2394		"#    Default 1: enable fdr10 when supported\n"
2395		"#    2: disable fdr10 when supported\n"
2396		"fdr10 %u\n\n"
2397		"# The subnet_timeout code that will be set for all the ports\n"
2398		"# The actual timeout is 4.096usec * 2^<subnet_timeout>\n"
2399		"subnet_timeout %u\n\n"
2400		"# Threshold of local phy errors for sending Trap 129\n"
2401		"local_phy_errors_threshold 0x%02x\n\n"
2402		"# Threshold of credit overrun errors for sending Trap 130\n"
2403		"overrun_errors_threshold 0x%02x\n\n"
2404		"# Use SwitchInfo:MulticastFDBTop if advertised in PortInfo:CapabilityMask\n"
2405		"use_mfttop %s\n\n",
2406		cl_ntoh64(p_opts->guid),
2407		cl_ntoh64(p_opts->m_key),
2408		cl_ntoh16(p_opts->m_key_lease_period),
2409		p_opts->m_key_protect_bits,
2410		p_opts->m_key_lookup ? "TRUE" : "FALSE",
2411		cl_ntoh64(p_opts->sm_key),
2412		cl_ntoh64(p_opts->sa_key),
2413		cl_ntoh64(p_opts->subnet_prefix),
2414		p_opts->lmc,
2415		p_opts->lmc_esp0 ? "TRUE" : "FALSE",
2416		p_opts->sm_sl,
2417		p_opts->packet_life_time,
2418		p_opts->vl_stall_count,
2419		p_opts->leaf_vl_stall_count,
2420		p_opts->head_of_queue_lifetime,
2421		p_opts->leaf_head_of_queue_lifetime,
2422		p_opts->max_op_vls,
2423		p_opts->force_link_speed,
2424		p_opts->force_link_speed_ext,
2425		p_opts->fdr10,
2426		p_opts->subnet_timeout,
2427		p_opts->local_phy_errors_threshold,
2428		p_opts->overrun_errors_threshold,
2429		p_opts->use_mfttop ? "TRUE" : "FALSE");
2430
2431	fprintf(out,
2432		"#\n# PARTITIONING OPTIONS\n#\n"
2433		"# Partition configuration file to be used\n"
2434		"partition_config_file %s\n\n"
2435		"# Disable partition enforcement by switches (DEPRECATED)\n"
2436		"# This option is DEPRECATED. Please use part_enforce instead\n"
2437		"no_partition_enforcement %s\n\n"
2438		"# Partition enforcement type (for switches)\n"
2439		"# Values are both, out, in and off\n"
2440		"# Default is both (outbound and inbound enforcement)\n"
2441		"part_enforce %s\n\n"
2442		"# Allow both full and limited membership on the same partition\n"
2443		"allow_both_pkeys %s\n\n"
2444		"# SM assigned GUID byte where GUID is formed from OpenFabrics OUI\n"
2445		"# followed by 40 bits xy 00 ab cd ef where xy is the SM assigned GUID byte\n"
2446		"# and ab cd ef is an SM autogenerated 24 bits\n"
2447		"# SM assigned GUID byte should be configured as subnet unique\n"
2448		"sm_assigned_guid 0x%02x\n\n",
2449		p_opts->partition_config_file,
2450		p_opts->no_partition_enforcement ? "TRUE" : "FALSE",
2451		p_opts->part_enforce,
2452		p_opts->allow_both_pkeys ? "TRUE" : "FALSE",
2453		p_opts->sm_assigned_guid);
2454
2455	fprintf(out,
2456		"#\n# SWEEP OPTIONS\n#\n"
2457		"# The number of seconds between subnet sweeps (0 disables it)\n"
2458		"sweep_interval %u\n\n"
2459		"# If TRUE cause all lids to be reassigned\n"
2460		"reassign_lids %s\n\n"
2461		"# If TRUE forces every sweep to be a heavy sweep\n"
2462		"force_heavy_sweep %s\n\n"
2463		"# If TRUE every trap 128 and 144 will cause a heavy sweep.\n"
2464		"# NOTE: successive identical traps (>10) are suppressed\n"
2465		"sweep_on_trap %s\n\n",
2466		p_opts->sweep_interval,
2467		p_opts->reassign_lids ? "TRUE" : "FALSE",
2468		p_opts->force_heavy_sweep ? "TRUE" : "FALSE",
2469		p_opts->sweep_on_trap ? "TRUE" : "FALSE");
2470
2471	fprintf(out,
2472		"#\n# ROUTING OPTIONS\n#\n"
2473		"# If TRUE count switches as link subscriptions\n"
2474		"port_profile_switch_nodes %s\n\n",
2475		p_opts->port_profile_switch_nodes ? "TRUE" : "FALSE");
2476
2477	fprintf(out,
2478		"# Name of file with port guids to be ignored by port profiling\n"
2479		"port_prof_ignore_file %s\n\n", p_opts->port_prof_ignore_file ?
2480		p_opts->port_prof_ignore_file : null_str);
2481
2482	fprintf(out,
2483		"# The file holding routing weighting factors per output port\n"
2484		"hop_weights_file %s\n\n",
2485		p_opts->hop_weights_file ? p_opts->hop_weights_file : null_str);
2486
2487	fprintf(out,
2488		"# The file holding non-default port order per switch for routing\n"
2489		"port_search_ordering_file %s\n\n",
2490		p_opts->port_search_ordering_file ?
2491		p_opts->port_search_ordering_file : null_str);
2492
2493	fprintf(out,
2494		"# Routing engine\n"
2495		"# Multiple routing engines can be specified separated by\n"
2496		"# commas so that specific ordering of routing algorithms will\n"
2497		"# be tried if earlier routing engines fail.\n"
2498		"# Supported engines: minhop, updn, dnup, file, ftree, lash,\n"
2499		"#    dor, torus-2QoS, dfsssp, sssp\n"
2500		"routing_engine %s\n\n", p_opts->routing_engine_names ?
2501		p_opts->routing_engine_names : null_str);
2502
2503	fprintf(out,
2504		"# Connect roots (use FALSE if unsure)\n"
2505		"connect_roots %s\n\n",
2506		p_opts->connect_roots ? "TRUE" : "FALSE");
2507
2508	fprintf(out,
2509		"# Use unicast routing cache (use FALSE if unsure)\n"
2510		"use_ucast_cache %s\n\n",
2511		p_opts->use_ucast_cache ? "TRUE" : "FALSE");
2512
2513	fprintf(out,
2514		"# Lid matrix dump file name\n"
2515		"lid_matrix_dump_file %s\n\n", p_opts->lid_matrix_dump_file ?
2516		p_opts->lid_matrix_dump_file : null_str);
2517
2518	fprintf(out,
2519		"# LFTs file name\nlfts_file %s\n\n",
2520		p_opts->lfts_file ? p_opts->lfts_file : null_str);
2521
2522	fprintf(out,
2523		"# The file holding the root node guids (for fat-tree or Up/Down)\n"
2524		"# One guid in each line\nroot_guid_file %s\n\n",
2525		p_opts->root_guid_file ? p_opts->root_guid_file : null_str);
2526
2527	fprintf(out,
2528		"# The file holding the fat-tree compute node guids\n"
2529		"# One guid in each line\ncn_guid_file %s\n\n",
2530		p_opts->cn_guid_file ? p_opts->cn_guid_file : null_str);
2531
2532	fprintf(out,
2533		"# The file holding the fat-tree I/O node guids\n"
2534		"# One guid in each line.\n"
2535		"# If only io_guid file is provided, the rest of nodes\n"
2536		"# are considered as compute nodes.\n"
2537		"io_guid_file %s\n\n",
2538		p_opts->io_guid_file ? p_opts->io_guid_file : null_str);
2539
2540        fprintf(out,
2541		"# If TRUE enables alternative indexing policy for ftree routing\n"
2542		"# in quasi-ftree topologies that can improve shift-pattern support.\n"
2543		"# The switch indexing starts from root switch and leaf switches\n"
2544		"# are termination points of BFS algorithm\n"
2545		"# If FALSE, the indexing starts from leaf switch (default)\n"
2546		"quasi_ftree_indexing %s\n\n",
2547		p_opts->quasi_ftree_indexing ? "TRUE" : "FALSE");
2548
2549	fprintf(out,
2550		"# Number of reverse hops allowed for I/O nodes\n"
2551		"# Used for connectivity between I/O nodes connected to Top Switches\nmax_reverse_hops %d\n\n",
2552		p_opts->max_reverse_hops);
2553
2554	fprintf(out,
2555		"# The file holding the node ids which will be used by"
2556		" Up/Down algorithm instead\n# of GUIDs (one guid and"
2557		" id in each line)\nids_guid_file %s\n\n",
2558		p_opts->ids_guid_file ? p_opts->ids_guid_file : null_str);
2559
2560	fprintf(out,
2561		"# The file holding guid routing order guids (for MinHop and Up/Down)\n"
2562		"guid_routing_order_file %s\n\n",
2563		p_opts->guid_routing_order_file ? p_opts->guid_routing_order_file : null_str);
2564
2565	fprintf(out,
2566		"# Do mesh topology analysis (for LASH algorithm)\n"
2567		"do_mesh_analysis %s\n\n",
2568		p_opts->do_mesh_analysis ? "TRUE" : "FALSE");
2569
2570	fprintf(out,
2571		"# Starting VL for LASH algorithm\n"
2572		"lash_start_vl %u\n\n",
2573		p_opts->lash_start_vl);
2574
2575	fprintf(out,
2576		"# Port Shifting (use FALSE if unsure)\n"
2577		"port_shifting %s\n\n",
2578		p_opts->port_shifting ? "TRUE" : "FALSE");
2579
2580	fprintf(out,
2581		"# Assign ports in a random order instead of round-robin\n"
2582		"# If zero disable (default), otherwise use the value as a random seed\n"
2583		"scatter_ports %d\n\n",
2584		p_opts->scatter_ports);
2585
2586	fprintf(out,
2587		"# Don't use scatter for ports defined in\n"
2588		"# guid_routing_order file\n"
2589		"guid_routing_order_no_scatter %s\n\n",
2590		p_opts->guid_routing_order_no_scatter ? "TRUE" : "FALSE");
2591
2592	fprintf(out,
2593		"# SA database file name\nsa_db_file %s\n\n",
2594		p_opts->sa_db_file ? p_opts->sa_db_file : null_str);
2595
2596	fprintf(out,
2597		"# If TRUE causes OpenSM to dump SA database at the end of\n"
2598		"# every light sweep, regardless of the verbosity level\n"
2599		"sa_db_dump %s\n\n",
2600		p_opts->sa_db_dump ? "TRUE" : "FALSE");
2601
2602	fprintf(out,
2603		"# Torus-2QoS configuration file name\ntorus_config %s\n\n",
2604		p_opts->torus_conf_file ? p_opts->torus_conf_file : null_str);
2605
2606	fprintf(out,
2607		"#\n# HANDOVER - MULTIPLE SMs OPTIONS\n#\n"
2608		"# SM priority used for deciding who is the master\n"
2609		"# Range goes from 0 (lowest priority) to 15 (highest).\n"
2610		"sm_priority %u\n\n"
2611		"# If TRUE other SMs on the subnet should be ignored\n"
2612		"ignore_other_sm %s\n\n"
2613		"# Timeout in [msec] between two polls of active master SM\n"
2614		"sminfo_polling_timeout %u\n\n"
2615		"# Number of failing polls of remote SM that declares it dead\n"
2616		"polling_retry_number %u\n\n"
2617		"# If TRUE honor the guid2lid file when coming out of standby\n"
2618		"# state, if such file exists and is valid\n"
2619		"honor_guid2lid_file %s\n\n",
2620		p_opts->sm_priority,
2621		p_opts->ignore_other_sm ? "TRUE" : "FALSE",
2622		p_opts->sminfo_polling_timeout,
2623		p_opts->polling_retry_number,
2624		p_opts->honor_guid2lid_file ? "TRUE" : "FALSE");
2625
2626	fprintf(out,
2627		"#\n# TIMING AND THREADING OPTIONS\n#\n"
2628		"# Maximum number of SMPs sent in parallel\n"
2629		"max_wire_smps %u\n\n"
2630		"# Maximum number of timeout based SMPs allowed to be outstanding\n"
2631		"# A value less than or equal to max_wire_smps disables this mechanism\n"
2632		"max_wire_smps2 %u\n\n"
2633		"# The timeout in [usec] used for sending SMPs above max_wire_smps limit\n"
2634		"# and below max_wire_smps2 limit\n"
2635		"max_smps_timeout %u\n\n"
2636		"# The maximum time in [msec] allowed for a transaction to complete\n"
2637		"transaction_timeout %u\n\n"
2638		"# The maximum number of retries allowed for a transaction to complete\n"
2639		"transaction_retries %u\n\n"
2640		"# Maximal time in [msec] a message can stay in the incoming message queue.\n"
2641		"# If there is more than one message in the queue and the last message\n"
2642		"# stayed in the queue more than this value, any SA request will be\n"
2643		"# immediately be dropped but BUSY status is not currently returned.\n"
2644		"max_msg_fifo_timeout %u\n\n"
2645		"# Use a single thread for handling SA queries\n"
2646		"single_thread %s\n\n",
2647		p_opts->max_wire_smps,
2648		p_opts->max_wire_smps2,
2649		p_opts->max_smps_timeout,
2650		p_opts->transaction_timeout,
2651		p_opts->transaction_retries,
2652		p_opts->max_msg_fifo_timeout,
2653		p_opts->single_thread ? "TRUE" : "FALSE");
2654
2655	fprintf(out,
2656		"#\n# MISC OPTIONS\n#\n"
2657		"# Daemon mode\n"
2658		"daemon %s\n\n"
2659		"# SM Inactive\n"
2660		"sm_inactive %s\n\n"
2661		"# Babbling Port Policy\n"
2662		"babbling_port_policy %s\n\n"
2663		"# Drop event subscriptions (InformInfo and ServiceRecord) on port removal and SM coming out of STANDBY\n"
2664		"drop_event_subscriptions %s\n\n"
2665		"# Validate IPoIB non-broadcast group creation parameters against\n"
2666		"# broadcast group parameters per IETF RFC 4391 (default TRUE)\n"
2667		"ipoib_mcgroup_creation_validation %s\n\n"
2668		"# Validate multicast join parameters against multicast group\n"
2669		"# parameters when MC group already exists\n"
2670		"mcgroup_join_validation %s\n\n"
2671		"# Use Optimized SLtoVLMapping programming if supported by device\n"
2672		"use_optimized_slvl %s\n\n"
2673		"# Sync in memory files used for high availability with storage\n"
2674		"fsync_high_avail_files %s\n\n",
2675		p_opts->daemon ? "TRUE" : "FALSE",
2676		p_opts->sm_inactive ? "TRUE" : "FALSE",
2677		p_opts->babbling_port_policy ? "TRUE" : "FALSE",
2678		p_opts->drop_event_subscriptions ? "TRUE" : "FALSE",
2679		p_opts->ipoib_mcgroup_creation_validation ? "TRUE" : "FALSE",
2680		p_opts->mcgroup_join_validation ? "TRUE" : "FALSE",
2681		p_opts->use_optimized_slvl ? "TRUE" : "FALSE",
2682		p_opts->fsync_high_avail_files ? "TRUE" : "FALSE");
2683
2684#ifdef ENABLE_OSM_PERF_MGR
2685	fprintf(out,
2686		"#\n# Performance Manager Options\n#\n"
2687		"# perfmgr enable\n"
2688		"# PerfMgr is enabled if TRUE and disabled if FALSE (default FALSE)\n"
2689		"perfmgr %s\n\n"
2690		"# redirection enable\n"
2691		"# Redirection supported if TRUE and not supported if FALSE (default TRUE)\n"
2692		"perfmgr_redir %s\n\n"
2693		"# sweep time in seconds (default %u seconds)\n"
2694		"perfmgr_sweep_time_s %u\n\n"
2695		"# Max outstanding queries (default %u)\n"
2696		"perfmgr_max_outstanding_queries %u\n\n"
2697		"# Ignore CAs on sweep (default FALSE)\n"
2698		"perfmgr_ignore_cas %s\n\n"
2699		"# Remove missing nodes from DB (default TRUE)\n"
2700		"perfmgr_rm_nodes %s\n\n"
2701		"# Log error counters to opensm.log (default TRUE)\n"
2702		"perfmgr_log_errors %s\n\n"
2703		"# Query PerfMgt Get(ClassPortInfo) for extended capabilities\n"
2704		"# Extended capabilities include 64 bit extended counters\n"
2705		"# and transmit wait support (default TRUE)\n"
2706		"perfmgr_query_cpi %s\n\n"
2707		"# Log xmit_wait errors (default FALSE)\n"
2708		"perfmgr_xmit_wait_log %s\n\n"
2709		"# If logging xmit_wait's; set threshold (default %u)\n"
2710		"perfmgr_xmit_wait_threshold %u\n\n"
2711		,
2712		p_opts->perfmgr ? "TRUE" : "FALSE",
2713		p_opts->perfmgr_redir ? "TRUE" : "FALSE",
2714		OSM_PERFMGR_DEFAULT_SWEEP_TIME_S,
2715		p_opts->perfmgr_sweep_time_s,
2716		OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES,
2717		p_opts->perfmgr_max_outstanding_queries,
2718		p_opts->perfmgr_ignore_cas ? "TRUE" : "FALSE",
2719		p_opts->perfmgr_rm_nodes ? "TRUE" : "FALSE",
2720		p_opts->perfmgr_log_errors ? "TRUE" : "FALSE",
2721		p_opts->perfmgr_query_cpi ? "TRUE" : "FALSE",
2722		p_opts->perfmgr_xmit_wait_log ? "TRUE" : "FALSE",
2723		OSM_PERFMGR_DEFAULT_XMIT_WAIT_THRESHOLD,
2724		p_opts->perfmgr_xmit_wait_threshold);
2725
2726	fprintf(out,
2727		"#\n# Event DB Options\n#\n"
2728		"# Dump file to dump the events to\n"
2729		"event_db_dump_file %s\n\n", p_opts->event_db_dump_file ?
2730		p_opts->event_db_dump_file : null_str);
2731#endif				/* ENABLE_OSM_PERF_MGR */
2732
2733	fprintf(out,
2734		"#\n# Event Plugin Options\n#\n"
2735		"# Event plugin name(s)\n"
2736		"event_plugin_name %s\n\n"
2737		"# Options string that would be passed to the plugin(s)\n"
2738		"event_plugin_options %s\n\n",
2739		p_opts->event_plugin_name ?
2740		p_opts->event_plugin_name : null_str,
2741		p_opts->event_plugin_options ?
2742		p_opts->event_plugin_options : null_str);
2743
2744	fprintf(out,
2745		"#\n# Node name map for mapping node's to more descriptive node descriptions\n"
2746		"# (man ibnetdiscover for more information)\n#\n"
2747		"node_name_map_name %s\n\n", p_opts->node_name_map_name ?
2748		p_opts->node_name_map_name : null_str);
2749
2750	fprintf(out,
2751		"#\n# DEBUG FEATURES\n#\n"
2752		"# The log flags used\n"
2753		"log_flags 0x%02x\n\n"
2754		"# Force flush of the log file after each log message\n"
2755		"force_log_flush %s\n\n"
2756		"# Log file to be used\n"
2757		"log_file %s\n\n"
2758		"# Limit the size of the log file in MB. If overrun, log is restarted\n"
2759		"log_max_size %u\n\n"
2760		"# If TRUE will accumulate the log over multiple OpenSM sessions\n"
2761		"accum_log_file %s\n\n"
2762		"# Per module logging configuration file\n"
2763		"# Each line in config file contains <module_name><separator><log_flags>\n"
2764		"# where module_name is file name including .c\n"
2765		"# separator is either = , space, or tab\n"
2766		"# log_flags is the same flags as used in the coarse/overall logging\n"
2767		"per_module_logging_file %s\n\n"
2768		"# The directory to hold the file OpenSM dumps\n"
2769		"dump_files_dir %s\n\n"
2770		"# If TRUE enables new high risk options and hardware specific quirks\n"
2771		"enable_quirks %s\n\n"
2772		"# If TRUE disables client reregistration\n"
2773		"no_clients_rereg %s\n\n"
2774		"# If TRUE OpenSM should disable multicast support and\n"
2775		"# no multicast routing is performed if TRUE\n"
2776		"disable_multicast %s\n\n"
2777		"# If TRUE opensm will exit on fatal initialization issues\n"
2778		"exit_on_fatal %s\n\n" "# console [off|local"
2779#ifdef ENABLE_OSM_CONSOLE_LOOPBACK
2780		"|loopback"
2781#endif
2782#ifdef ENABLE_OSM_CONSOLE_SOCKET
2783		"|socket]\n"
2784#else
2785		"]\n"
2786#endif
2787		"console %s\n\n"
2788		"# Telnet port for console (default %d)\n"
2789		"console_port %d\n\n",
2790		p_opts->log_flags,
2791		p_opts->force_log_flush ? "TRUE" : "FALSE",
2792		p_opts->log_file,
2793		p_opts->log_max_size,
2794		p_opts->accum_log_file ? "TRUE" : "FALSE",
2795		p_opts->per_module_logging_file ?
2796			p_opts->per_module_logging_file : null_str,
2797		p_opts->dump_files_dir,
2798		p_opts->enable_quirks ? "TRUE" : "FALSE",
2799		p_opts->no_clients_rereg ? "TRUE" : "FALSE",
2800		p_opts->disable_multicast ? "TRUE" : "FALSE",
2801		p_opts->exit_on_fatal ? "TRUE" : "FALSE",
2802		p_opts->console,
2803		OSM_DEFAULT_CONSOLE_PORT, p_opts->console_port);
2804
2805	fprintf(out,
2806		"#\n# QoS OPTIONS\n#\n"
2807		"# Enable QoS setup\n"
2808		"qos %s\n\n"
2809		"# QoS policy file to be used\n"
2810		"qos_policy_file %s\n"
2811		"# Supress QoS MAD status errors\n"
2812		"suppress_sl2vl_mad_status_errors %s\n\n",
2813		p_opts->qos ? "TRUE" : "FALSE", p_opts->qos_policy_file,
2814		p_opts->suppress_sl2vl_mad_status_errors ? "TRUE" : "FALSE");
2815
2816	subn_dump_qos_options(out,
2817			      "QoS default options", "qos",
2818			      &p_opts->qos_options);
2819	fprintf(out, "\n");
2820	subn_dump_qos_options(out,
2821			      "QoS CA options", "qos_ca",
2822			      &p_opts->qos_ca_options);
2823	fprintf(out, "\n");
2824	subn_dump_qos_options(out,
2825			      "QoS Switch Port 0 options", "qos_sw0",
2826			      &p_opts->qos_sw0_options);
2827	fprintf(out, "\n");
2828	subn_dump_qos_options(out,
2829			      "QoS Switch external ports options", "qos_swe",
2830			      &p_opts->qos_swe_options);
2831	fprintf(out, "\n");
2832	subn_dump_qos_options(out,
2833			      "QoS Router ports options", "qos_rtr",
2834			      &p_opts->qos_rtr_options);
2835	fprintf(out, "\n");
2836
2837	fprintf(out,
2838		"#\n# Congestion Control OPTIONS (EXPERIMENTAL)\n#\n\n"
2839		"# Enable Congestion Control Configuration\n"
2840		"congestion_control %s\n\n"
2841		"# CCKey to use when configuring congestion control\n"
2842		"# note that this does not configure a new CCkey, only the CCkey to use\n"
2843		"cc_key 0x%016" PRIx64 "\n\n"
2844		"# Congestion Control Max outstanding MAD\n"
2845		"cc_max_outstanding_mads %u\n\n",
2846		p_opts->congestion_control ? "TRUE" : "FALSE",
2847		cl_ntoh64(p_opts->cc_key),
2848		p_opts->cc_max_outstanding_mads);
2849
2850	fprintf(out,
2851		"#\n# Congestion Control SwitchCongestionSetting options\n#\n"
2852		"# Control Map - bitmask indicating which of the following are to be used\n"
2853		"# bit 0 - victim mask\n"
2854		"# bit 1 - credit mask\n"
2855		"# bit 2 - threshold + packet size\n"
2856		"# bit 3 - credit starvation threshold + return delay valid\n"
2857		"# bit 4 - marking rate valid\n"
2858		"cc_sw_cong_setting_control_map 0x%X\n\n",
2859		cl_ntoh32(p_opts->cc_sw_cong_setting_control_map));
2860
2861	fprintf(out,
2862		"# Victim Mask - 256 bit mask representing switch ports, mark packets with FECN\n"
2863		"# whether they are the source or victim of congestion\n"
2864		"# bit 0 - port 0 (enhanced port)\n"
2865		"# bit 1 - port 1\n"
2866		"# ...\n"
2867		"# bit 254 - port 254\n"
2868		"# bit 255 - reserved\n"
2869		"cc_sw_cong_setting_victim_mask 0x");
2870
2871	for (i = 0; i < IB_CC_PORT_MASK_DATA_SIZE; i++)
2872		fprintf(out, "%02X", p_opts->cc_sw_cong_setting_victim_mask[i]);
2873	fprintf(out, "\n\n");
2874
2875	fprintf(out,
2876		"# Credit Mask - 256 bit mask representing switch ports to apply credit starvation\n"
2877		"# bit 0 - port 0 (enhanced port)\n"
2878		"# bit 1 - port 1\n"
2879		"# ...\n"
2880		"# bit 254 - port 254\n"
2881		"# bit 255 - reserved\n"
2882		"cc_sw_cong_setting_credit_mask 0x");
2883
2884	for (i = 0; i < IB_CC_PORT_MASK_DATA_SIZE; i++)
2885		fprintf(out, "%02X", p_opts->cc_sw_cong_setting_credit_mask[i]);
2886	fprintf(out, "\n\n");
2887
2888	fprintf(out,
2889		"# Threshold - value indicating aggressiveness of congestion marking\n"
2890		"# 0x0 - none, 0x1 - loose, ..., 0xF - aggressive\n"
2891		"cc_sw_cong_setting_threshold 0x%02X\n\n"
2892		"# Packet Size - any packet less than this size will not be marked with a FECN\n"
2893		"# units are in credits\n"
2894		"cc_sw_cong_setting_packet_size %u\n\n"
2895		"# Credit Starvation Threshold - value indicating aggressiveness of credit starvation\n"
2896		"# 0x0 - none, 0x1 - loose, ..., 0xF - aggressive\n"
2897		"cc_sw_cong_setting_credit_starvation_threshold 0x%02X\n\n"
2898		"# Credit Starvation Return Delay - in CCT entry shift:multiplier format, see IB spec\n"
2899		"cc_sw_cong_setting_credit_starvation_return_delay %u:%u\n\n"
2900		"# Marking Rate - mean number of packets between markings\n"
2901		"cc_sw_cong_setting_marking_rate %u\n\n",
2902		p_opts->cc_sw_cong_setting_threshold,
2903		p_opts->cc_sw_cong_setting_packet_size,
2904		p_opts->cc_sw_cong_setting_credit_starvation_threshold,
2905		p_opts->cc_sw_cong_setting_credit_starvation_return_delay.shift,
2906		p_opts->cc_sw_cong_setting_credit_starvation_return_delay.multiplier,
2907		cl_ntoh16(p_opts->cc_sw_cong_setting_marking_rate));
2908
2909	fprintf(out,
2910		"#\n# Congestion Control CA Congestion Setting options\n#\n"
2911		"# Port Control\n"
2912		"# bit 0 = 0, QP based congestion control\n"
2913		"# bit 0 = 1, SL/port based congestion control\n"
2914		"cc_ca_cong_setting_port_control 0x%04X\n\n"
2915		"# Control Map - 16 bit bitmask indicating which SLs should be configured\n"
2916		"cc_ca_cong_setting_control_map 0x%04X\n\n",
2917		cl_ntoh16(p_opts->cc_ca_cong_setting_port_control),
2918		cl_ntoh16(p_opts->cc_ca_cong_setting_control_map));
2919
2920	fprintf(out,
2921		"#\n# CA Congestion Setting Entries\n#\n"
2922		"# Each of congestion control settings below configures the CA Congestion\n"
2923		"# Settings for an individual SL.  The SL must be specified before the value.\n"
2924		"# These options may be specified multiple times to configure different values\n"
2925		"# for different SLs.\n"
2926		"#\n"
2927		"# ccti timer - when expires decrements 1 from the CCTI\n"
2928		"# ccti increase - number to be added to the table index on receipt of a BECN\n"
2929		"# trigger threshold - when the ccti is equal to this, an event is logged\n"
2930		"# ccti min - the minimum value for the ccti.  This imposes a minimum rate\n"
2931		"#            on the injection rate\n\n");
2932
2933	for (i = 0; i < IB_CA_CONG_ENTRY_DATA_SIZE; i++) {
2934		/* Don't output unless one of the settings has been set, there's no need
2935		 * to output 16 chunks of this with all defaults of 0 */
2936		if (p_opts->cc_ca_cong_entries[i].ccti_timer
2937		    || p_opts->cc_ca_cong_entries[i].ccti_increase
2938		    || p_opts->cc_ca_cong_entries[i].trigger_threshold
2939		    || p_opts->cc_ca_cong_entries[i].ccti_min) {
2940			fprintf(out,
2941				"# SL = %u\n"
2942				"cc_ca_cong_setting_ccti_timer %u %u\n"
2943				"cc_ca_cong_setting_ccti_increase %u %u\n"
2944				"cc_ca_cong_setting_trigger_threshold %u %u\n"
2945				"cc_ca_cong_setting_ccti_min %u %u\n\n",
2946				i,
2947				i,
2948				cl_ntoh16(p_opts->cc_ca_cong_entries[i].ccti_timer),
2949				i,
2950				p_opts->cc_ca_cong_entries[i].ccti_increase,
2951				i,
2952				p_opts->cc_ca_cong_entries[i].trigger_threshold,
2953				i,
2954				p_opts->cc_ca_cong_entries[i].ccti_min);
2955			cacongoutputcount++;
2956		}
2957	}
2958
2959	/* If by chance all the CA Cong Settings are default, output at least 1 chunk
2960         * for illustration */
2961	if (!cacongoutputcount)
2962		fprintf(out,
2963			"# SL = 0\n"
2964			"cc_ca_cong_setting_ccti_timer 0 %u\n"
2965			"cc_ca_cong_setting_ccti_increase 0 %u\n"
2966			"cc_ca_cong_setting_trigger_threshold 0 %u\n"
2967			"cc_ca_cong_setting_ccti_min 0 %u\n\n",
2968			cl_ntoh16(p_opts->cc_ca_cong_entries[0].ccti_timer),
2969			p_opts->cc_ca_cong_entries[0].ccti_increase,
2970			p_opts->cc_ca_cong_entries[0].trigger_threshold,
2971			p_opts->cc_ca_cong_entries[0].ccti_min);
2972
2973	fprintf(out,
2974		"#\n# Congestion Control Table\n#\n"
2975		"# Comma separated list of CCT entries representing CCT.\n"
2976		"# Format is shift:multipler,shift_multiplier,shift:multiplier,...\n"
2977		"cc_cct ");
2978
2979	if (!p_opts->cc_cct.entries_len) {
2980		fprintf(out, "%s\n", null_str);
2981	}
2982	else {
2983		fprintf(out, "%u:%u",
2984			p_opts->cc_cct.entries[0].shift,
2985			p_opts->cc_cct.entries[0].multiplier);
2986		for (i = 1; i < p_opts->cc_cct.entries_len; i++) {
2987			fprintf(out, ",%u:%u",
2988				p_opts->cc_cct.entries[i].shift,
2989				p_opts->cc_cct.entries[i].multiplier);
2990		}
2991		fprintf(out, "\n");
2992	}
2993	fprintf(out, "\n");
2994
2995	fprintf(out,
2996		"# Prefix routes file name\n"
2997		"prefix_routes_file %s\n\n",
2998		p_opts->prefix_routes_file);
2999
3000	fprintf(out,
3001		"#\n# IPv6 Solicited Node Multicast (SNM) Options\n#\n"
3002		"consolidate_ipv6_snm_req %s\n\n",
3003		p_opts->consolidate_ipv6_snm_req ? "TRUE" : "FALSE");
3004
3005	fprintf(out, "# Log prefix\nlog_prefix %s\n\n", p_opts->log_prefix);
3006
3007	/* optional string attributes ... */
3008
3009}
3010
3011int osm_subn_write_conf_file(char *file_name, IN osm_subn_opt_t * p_opts)
3012{
3013	FILE *opts_file;
3014
3015	opts_file = fopen(file_name, "w");
3016	if (!opts_file) {
3017		printf("cannot open file \'%s\' for writing: %s\n",
3018			file_name, strerror(errno));
3019		return -1;
3020	}
3021
3022	osm_subn_output_conf(opts_file, p_opts);
3023
3024	fclose(opts_file);
3025
3026	return 0;
3027}
3028