osm_prtn_config.c revision 331769
1/*
2 * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2012-2015 Mellanox Technologies LTD. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses.  You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 *     Redistribution and use in source and binary forms, with or
12 *     without modification, are permitted provided that the following
13 *     conditions are met:
14 *
15 *      - Redistributions of source code must retain the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer.
18 *
19 *      - Redistributions in binary form must reproduce the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer in the documentation and/or other materials
22 *        provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 */
34
35/*
36 * Abstract:
37 *    Implementation of opensm partition management configuration
38 */
39
40#if HAVE_CONFIG_H
41#  include <config.h>
42#endif				/* HAVE_CONFIG_H */
43
44#include <stdlib.h>
45#include <stdio.h>
46#include <string.h>
47#include <errno.h>
48#include <ctype.h>
49
50#include <iba/ib_types.h>
51#include <opensm/osm_file_ids.h>
52#define FILE_ID OSM_FILE_PRTN_CONFIG_C
53#include <opensm/osm_base.h>
54#include <opensm/osm_partition.h>
55#include <opensm/osm_subnet.h>
56#include <opensm/osm_log.h>
57#include <arpa/inet.h>
58#include <sys/socket.h>
59
60typedef enum {
61	LIMITED,
62	FULL,
63	BOTH
64} membership_t;
65
66const ib_gid_t osm_ipoib_broadcast_mgid = {
67	{
68	 0xff,			/*  multicast field */
69	 0x12,			/*  non-permanent bit, link local scope */
70	 0x40, 0x1b,		/*  IPv4 signature */
71	 0xff, 0xff,		/*  16 bits of P_Key (to be filled in) */
72	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/*  48 bits of zeros */
73	 0xff, 0xff, 0xff, 0xff,	/*  32 bit IPv4 broadcast address */
74	 },
75};
76
77struct group_flags {
78	unsigned mtu, rate, sl, scope_mask;
79	uint32_t Q_Key;
80	uint8_t TClass;
81	uint32_t FlowLabel;
82};
83
84struct precreate_mgroup {
85	ib_gid_t mgid;
86	struct group_flags flags;
87};
88
89struct part_conf {
90	osm_log_t *p_log;
91	osm_subn_t *p_subn;
92	osm_prtn_t *p_prtn;
93	unsigned is_ipoib;
94	struct group_flags flags;
95	membership_t membership;
96	boolean_t indx0;
97};
98
99extern osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn,
100				     const char *name, uint16_t pkey);
101extern ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, osm_subn_t * p_subn,
102					osm_prtn_t * p, unsigned type,
103					boolean_t full, boolean_t indx0);
104extern ib_api_status_t osm_prtn_add_port(osm_log_t * p_log,
105					 osm_subn_t * p_subn, osm_prtn_t * p,
106					 ib_net64_t guid, boolean_t full,
107					 boolean_t indx0);
108
109ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, osm_subn_t * p_subn,
110				     osm_prtn_t * p, uint8_t rate, uint8_t mtu,
111				     uint8_t sl, uint8_t scope, uint32_t Q_Key,
112				     uint8_t TClass, uint32_t FlowLabel,
113				     const ib_gid_t *mgid);
114
115
116static inline boolean_t mgid_is_broadcast(const ib_gid_t *mgid)
117{
118	return (memcmp(mgid, &osm_ipoib_broadcast_mgid,
119			sizeof(osm_ipoib_broadcast_mgid)) == 0);
120}
121
122static inline boolean_t mgid_is_ip(const ib_gid_t *mgid)
123{
124	ib_net16_t ipsig = *(ib_net16_t *)&mgid->raw[2];
125	return (ipsig == cl_hton16(0x401b) || ipsig == cl_hton16(0x601b));
126}
127
128static inline boolean_t ip_mgroup_pkey_ok(struct part_conf *conf,
129					  struct precreate_mgroup *group)
130{
131	ib_net16_t mpkey = *(ib_net16_t *)&group->mgid.raw[4];
132	char gid_str[INET6_ADDRSTRLEN];
133
134	if (mgid_is_broadcast(&group->mgid)
135	    /* user requested "wild card" of pkey */
136	    || mpkey == 0x0000
137	    /* user was smart enough to match */
138	    || mpkey == (conf->p_prtn->pkey | cl_hton16(0x8000)))
139		return (TRUE);
140
141	OSM_LOG(conf->p_log, OSM_LOG_ERROR,
142		"IP MC group (%s) specified with invalid pkey 0x%04x "
143		"for partition pkey = 0x%04x (%s)\n",
144		inet_ntop(AF_INET6, group->mgid.raw, gid_str, sizeof gid_str),
145		cl_ntoh16(mpkey), cl_ntoh16(conf->p_prtn->pkey), conf->p_prtn->name);
146	return (FALSE);
147}
148
149static inline boolean_t ip_mgroup_rate_ok(struct part_conf *conf,
150				struct precreate_mgroup *group)
151{
152	char gid_str[INET6_ADDRSTRLEN];
153
154	if (group->flags.rate == conf->flags.rate)
155		return (TRUE);
156
157	OSM_LOG(conf->p_log, OSM_LOG_ERROR,
158		"IP MC group (%s) specified with invalid rate (%d): "
159		"partition pkey = 0x%04x (%s) "
160		"[Partition broadcast group rate = %d]\n",
161		inet_ntop(AF_INET6, group->mgid.raw, gid_str, sizeof gid_str),
162		group->flags.rate, cl_ntoh16(conf->p_prtn->pkey),
163		conf->p_prtn->name, conf->flags.rate);
164	return (FALSE);
165}
166
167static inline boolean_t ip_mgroup_mtu_ok(struct part_conf *conf,
168				struct precreate_mgroup *group)
169{
170	char gid_str[INET6_ADDRSTRLEN];
171
172	if (group->flags.mtu == conf->flags.mtu)
173		return (TRUE);
174
175	OSM_LOG(conf->p_log, OSM_LOG_ERROR,
176		"IP MC group (%s) specified with invalid mtu (%d): "
177		"partition pkey = 0x%04x (%s) "
178		"[Partition broadcast group mtu = %d]\n",
179		inet_ntop(AF_INET6, group->mgid.raw, gid_str, sizeof gid_str),
180		group->flags.mtu, cl_ntoh16(conf->p_prtn->pkey),
181		conf->p_prtn->name, conf->flags.mtu);
182	return (FALSE);
183}
184
185static void __create_mgrp(struct part_conf *conf, struct precreate_mgroup *group)
186{
187	unsigned int scope;
188
189	if (!group->flags.scope_mask) {
190		osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn,
191				     (uint8_t) group->flags.rate,
192				     (uint8_t) group->flags.mtu,
193				     group->flags.sl,
194				     0,
195				     group->flags.Q_Key,
196				     group->flags.TClass,
197				     group->flags.FlowLabel,
198				     &group->mgid);
199	} else {
200		for (scope = 0; scope < 16; scope++) {
201			if (((1<<scope) & group->flags.scope_mask) == 0)
202				continue;
203
204			osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn,
205					     (uint8_t)group->flags.rate,
206					     (uint8_t)group->flags.mtu,
207					     (uint8_t)group->flags.sl,
208					     (uint8_t)scope,
209					     group->flags.Q_Key,
210					     group->flags.TClass,
211					     group->flags.FlowLabel,
212					     &group->mgid);
213		}
214	}
215}
216
217static int partition_create(unsigned lineno, struct part_conf *conf,
218			    char *name, char *id, char *flag, char *flag_val)
219{
220	ib_net16_t pkey;
221
222	if (!id && name && isdigit(*name)) {
223		id = name;
224		name = NULL;
225	}
226
227	if (id) {
228		char *end;
229
230		pkey = cl_hton16((uint16_t)strtoul(id, &end, 0));
231		if (end == id || *end)
232			return -1;
233	} else
234		pkey = 0;
235
236	conf->p_prtn = osm_prtn_make_new(conf->p_log, conf->p_subn,
237					 name, pkey);
238	if (!conf->p_prtn)
239		return -1;
240
241	if (!conf->p_subn->opt.qos && conf->flags.sl != OSM_DEFAULT_SL) {
242		OSM_LOG(conf->p_log, OSM_LOG_DEBUG, "Overriding SL %d"
243			" to default SL %d on partition %s"
244			" as QoS is not enabled.\n",
245			conf->flags.sl, OSM_DEFAULT_SL, name);
246		conf->flags.sl = OSM_DEFAULT_SL;
247	}
248	conf->p_prtn->sl = (uint8_t) conf->flags.sl;
249
250	if (conf->is_ipoib) {
251		struct precreate_mgroup broadcast_mgroup;
252		memset(&broadcast_mgroup, 0, sizeof(broadcast_mgroup));
253		broadcast_mgroup.mgid = osm_ipoib_broadcast_mgid;
254		pkey = CL_HTON16(0x8000) | conf->p_prtn->pkey;
255		memcpy(&broadcast_mgroup.mgid.raw[4], &pkey , sizeof(pkey));
256		broadcast_mgroup.flags.mtu = conf->flags.mtu;
257		broadcast_mgroup.flags.rate = conf->flags.rate;
258		broadcast_mgroup.flags.sl = conf->flags.sl;
259		broadcast_mgroup.flags.Q_Key = conf->flags.Q_Key ?
260						conf->flags.Q_Key :
261						OSM_IPOIB_BROADCAST_MGRP_QKEY;
262		broadcast_mgroup.flags.TClass = conf->flags.TClass;
263		broadcast_mgroup.flags.FlowLabel = conf->flags.FlowLabel;
264		__create_mgrp(conf, &broadcast_mgroup);
265	}
266
267	return 0;
268}
269
270/* returns 1 if processed 0 if _not_ */
271static int parse_group_flag(unsigned lineno, osm_log_t * p_log,
272			    struct group_flags *flags,
273			    char *flag, char *val)
274{
275	int rc = 0;
276	int len = strlen(flag);
277	if (!strncmp(flag, "mtu", len)) {
278		rc = 1;
279		if (!val || (flags->mtu = strtoul(val, NULL, 0)) == 0)
280			OSM_LOG(p_log, OSM_LOG_VERBOSE,
281				"PARSE WARN: line %d: "
282				"flag \'mtu\' requires valid value"
283				" - skipped\n", lineno);
284	} else if (!strncmp(flag, "rate", len)) {
285		rc = 1;
286		if (!val || (flags->rate = strtoul(val, NULL, 0)) == 0)
287			OSM_LOG(p_log, OSM_LOG_VERBOSE,
288				"PARSE WARN: line %d: "
289				"flag \'rate\' requires valid value"
290				" - skipped\n", lineno);
291	} else if (!strncmp(flag, "scope", len)) {
292		unsigned int scope;
293		rc = 1;
294		if (!val || (scope = strtoul(val, NULL, 0)) == 0 || scope > 0xF)
295			OSM_LOG(p_log, OSM_LOG_VERBOSE,
296				"PARSE WARN: line %d: "
297				"flag \'scope\' requires valid value"
298				" - skipped\n", lineno);
299		else
300			flags->scope_mask |= (1<<scope);
301	} else if (!strncmp(flag, "Q_Key", strlen(flag))) {
302		rc = 1;
303		if (!val || (flags->Q_Key = strtoul(val, NULL, 0)) == 0)
304			OSM_LOG(p_log, OSM_LOG_VERBOSE,
305				"PARSE WARN: line %d: "
306				"flag \'Q_Key\' requires valid value"
307				" - using '0'\n", lineno);
308	} else if (!strncmp(flag, "TClass", strlen(flag))) {
309		rc =1;
310		if (!val || (flags->TClass = strtoul(val, NULL, 0)) == 0)
311			OSM_LOG(p_log, OSM_LOG_VERBOSE,
312				"PARSE WARN: line %d: "
313				"flag \'TClass\' requires valid value"
314				" - using '0'\n", lineno);
315	} else if (!strncmp(flag, "sl", len)) {
316		unsigned sl;
317		char *end;
318		rc = 1;
319
320		if (!val || !*val || (sl = strtoul(val, &end, 0)) > 15 ||
321		    (*end && !isspace(*end)))
322			OSM_LOG(p_log, OSM_LOG_VERBOSE,
323				"PARSE WARN: line %d: "
324				"flag \'sl\' requires valid value"
325				" - skipped\n", lineno);
326		else
327			flags->sl = sl;
328	} else if (!strncmp(flag, "FlowLabel", len)) {
329		uint32_t FlowLabel;
330		char *end;
331		rc = 1;
332
333		if (!val || !*val ||
334		    (FlowLabel = strtoul(val, &end, 0)) > 0xFFFFF ||
335		    (*end && !isspace(*end)))
336			OSM_LOG(p_log, OSM_LOG_VERBOSE,
337				"PARSE WARN: line %d: "
338				"flag \'FlowLabel\' requires valid value"
339				" - skipped\n", lineno);
340		else
341			flags->FlowLabel = FlowLabel;
342	}
343
344	return rc;
345}
346
347static int partition_add_flag(unsigned lineno, struct part_conf *conf,
348			      char *flag, char *val)
349{
350	int len = strlen(flag);
351
352	/* ipoib gc group flags are processed here. */
353	if (parse_group_flag(lineno, conf->p_log, &conf->flags, flag, val))
354		return 0;
355
356	/* partition flags go here. */
357	if (!strncmp(flag, "ipoib", len)) {
358		conf->is_ipoib = 1;
359	} else if (!strncmp(flag, "defmember", len)) {
360		if (!val || (strncmp(val, "limited", strlen(val))
361			     && strncmp(val, "both", strlen(val))
362			     && strncmp(val, "full", strlen(val))))
363			OSM_LOG(conf->p_log, OSM_LOG_VERBOSE,
364				"PARSE WARN: line %d: "
365				"flag \'defmember\' requires valid value (limited or full or both)"
366				" - skipped\n", lineno);
367		else {
368			if (!strncmp(val, "full", strlen(val)))
369				conf->membership = FULL;
370			else if (!strncmp(val, "both", strlen(val)))
371				conf->membership = BOTH;
372			else
373				conf->membership = LIMITED;
374		}
375	} else if (!strcmp(flag, "indx0"))
376		conf->indx0 = TRUE;
377	else {
378		OSM_LOG(conf->p_log, OSM_LOG_VERBOSE,
379			"PARSE WARN: line %d: "
380			"unrecognized partition flag \'%s\'"
381			" - ignored\n", lineno, flag);
382	}
383	return 0;
384}
385static void manage_membership_change(struct part_conf *conf, osm_prtn_t * p,
386				     unsigned type, membership_t membership,
387				     ib_net64_t guid)
388{
389	cl_map_t *p_tbl;
390	cl_map_iterator_t p_next, p_item;
391	osm_physp_t *p_physp;
392
393	/* In allow_both_pkeys mode */
394	/* if membership of the PKEY is set to FULL */
395	/* need to clean up the part_guid_tbl table entry for this guid */
396	/* if membership of the PKEY is set to LIMITED */
397	/* need to clean up the full_guid_tbl table entry for this guid */
398	/* as it could be populated because of previous definitions */
399
400	if (!conf->p_subn->opt.allow_both_pkeys || membership == BOTH)
401		return;
402
403	switch (type){
404	/* ALL = 0 */
405	case 0:
406		cl_map_remove_all(membership == LIMITED ?
407				  &p->full_guid_tbl : &p->part_guid_tbl);
408		break;
409	/* specific GUID */
410	case 0xFF:
411		cl_map_remove(membership == LIMITED ?
412			      &p->full_guid_tbl : &p->part_guid_tbl,
413			      cl_hton64(guid));
414		break;
415
416	case IB_NODE_TYPE_CA:
417	case IB_NODE_TYPE_SWITCH:
418	case IB_NODE_TYPE_ROUTER:
419		p_tbl = (membership == LIMITED) ?
420			 &p->full_guid_tbl : &p->part_guid_tbl;
421
422		p_next = cl_map_head(p_tbl);
423		while (p_next != cl_map_end(p_tbl)) {
424			p_item = p_next;
425			p_next = cl_map_next(p_item);
426			p_physp = (osm_physp_t *) cl_map_obj(p_item);
427			if (osm_node_get_type(p_physp->p_node) == type)
428				cl_map_remove_item(p_tbl, p_item);
429		}
430		break;
431	default:
432		break;
433
434	}
435}
436static int partition_add_all(struct part_conf *conf, osm_prtn_t * p,
437			     unsigned type, membership_t membership)
438{
439	manage_membership_change(conf, p, type, membership, 0);
440
441	if (membership != LIMITED &&
442	    osm_prtn_add_all(conf->p_log, conf->p_subn, p, type, TRUE, conf->indx0) != IB_SUCCESS)
443		return -1;
444	if ((membership == LIMITED ||
445	     (membership == BOTH && conf->p_subn->opt.allow_both_pkeys)) &&
446	    osm_prtn_add_all(conf->p_log, conf->p_subn, p, type, FALSE, conf->indx0) != IB_SUCCESS)
447		return -1;
448	return 0;
449}
450
451static int partition_add_port(unsigned lineno, struct part_conf *conf,
452			      char *name, char *flag)
453{
454	osm_prtn_t *p = conf->p_prtn;
455	ib_net64_t guid;
456	membership_t membership = conf->membership;
457
458	if (!name || !*name || !strncmp(name, "NONE", strlen(name)))
459		return 0;
460
461	if (flag) {
462		/* reset default membership to limited */
463		membership = LIMITED;
464		if (!strncmp(flag, "full", strlen(flag)))
465			membership = FULL;
466		else if (!strncmp(flag, "both", strlen(flag)))
467			membership = BOTH;
468		else if (strncmp(flag, "limited", strlen(flag))) {
469			OSM_LOG(conf->p_log, OSM_LOG_VERBOSE,
470				"PARSE WARN: line %d: "
471				"unrecognized port flag \'%s\'."
472				" Assume \'limited\'\n", lineno, flag);
473		}
474	}
475
476	if (!strncmp(name, "ALL", strlen(name)))
477		return partition_add_all(conf, p, 0, membership);
478	else if (!strncmp(name, "ALL_CAS", strlen(name)))
479		return partition_add_all(conf, p, IB_NODE_TYPE_CA, membership);
480	else if (!strncmp(name, "ALL_SWITCHES", strlen(name)))
481		return partition_add_all(conf, p, IB_NODE_TYPE_SWITCH,
482					 membership);
483	else if (!strncmp(name, "ALL_ROUTERS", strlen(name)))
484		return partition_add_all(conf, p, IB_NODE_TYPE_ROUTER,
485					 membership);
486	else if (!strncmp(name, "SELF", strlen(name))) {
487		guid = cl_ntoh64(conf->p_subn->sm_port_guid);
488	} else {
489		char *end;
490		guid = strtoull(name, &end, 0);
491		if (!guid || *end)
492			return -1;
493	}
494
495	manage_membership_change(conf, p, 0xFF, membership, guid);
496	if (membership != LIMITED &&
497	    osm_prtn_add_port(conf->p_log, conf->p_subn, p,
498			      cl_hton64(guid), TRUE, conf->indx0) != IB_SUCCESS)
499		return -1;
500	if ((membership == LIMITED ||
501	    (membership == BOTH && conf->p_subn->opt.allow_both_pkeys)) &&
502	    osm_prtn_add_port(conf->p_log, conf->p_subn, p,
503			      cl_hton64(guid), FALSE, conf->indx0) != IB_SUCCESS)
504		return -1;
505	return 0;
506}
507
508/* conf file parser */
509
510#define STRIP_HEAD_SPACES(p) while (*(p) == ' ' || *(p) == '\t' || \
511		*(p) == '\n') { (p)++; }
512#define STRIP_TAIL_SPACES(p) { char *q = (p) + strlen(p); \
513				while ( q != (p) && ( *q == '\0' || \
514					*q == ' ' || *q == '\t' || \
515					*q == '\n')) { *q-- = '\0'; }; }
516
517static int parse_name_token(char *str, char **name, char **val)
518{
519	int len = 0;
520	char *p, *q;
521
522	*name = *val = NULL;
523
524	p = str;
525
526	while (*p == ' ' || *p == '\t' || *p == '\n')
527		p++;
528
529	q = strchr(p, '=');
530	if (q)
531		*q++ = '\0';
532
533	len = strlen(str) + 1;
534	str = q;
535
536	q = p + strlen(p);
537	while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n'))
538		*q-- = '\0';
539
540	*name = p;
541
542	p = str;
543	if (!p)
544		return len;
545
546	while (*p == ' ' || *p == '\t' || *p == '\n')
547		p++;
548
549	q = p + strlen(p);
550	len += (int)(q - str) + 1;
551	while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n'))
552		*q-- = '\0';
553	*val = p;
554
555	return len;
556}
557
558static int parse_mgroup_flags(osm_log_t * p_log,
559				struct precreate_mgroup *mgroup,
560				char *p, unsigned lineno)
561{
562	int ret, len = 0;
563	char *flag, *val, *q;
564	do {
565		flag = val = NULL;
566		q = strchr(p, ',');
567		if (q)
568			*q++ = '\0';
569
570		ret = parse_name_token(p, &flag, &val);
571
572		if (!parse_group_flag(lineno, p_log, &mgroup->flags,
573				     flag, val)) {
574			OSM_LOG(p_log, OSM_LOG_VERBOSE,
575				"PARSE WARN: line %d: "
576				"unrecognized mgroup flag \'%s\'"
577				" - ignored\n", lineno, flag);
578		}
579		p += ret;
580		len += ret;
581	} while (q);
582
583	return (len);
584}
585
586static int mgroup_create(char *p, char *mgid, unsigned lineno, struct part_conf *conf)
587{
588	int ret = 0;
589	struct precreate_mgroup mgroup;
590
591	memset(&mgroup, 0, sizeof(mgroup));
592
593	if (inet_pton(AF_INET6, mgid, &mgroup.mgid) != 1
594	    || mgroup.mgid.raw[0] != 0xff) {
595		OSM_LOG(conf->p_log, OSM_LOG_ERROR,
596			"PARSE ERROR partition conf file line %d: "
597			"mgid \"%s\": gid is not multicast\n", lineno, mgid);
598		return 0;
599	}
600
601	/* inherit partition flags */
602	mgroup.flags.mtu = conf->flags.mtu;
603	mgroup.flags.rate = conf->flags.rate;
604	mgroup.flags.sl = conf->flags.sl;
605	mgroup.flags.Q_Key = conf->flags.Q_Key;
606	mgroup.flags.FlowLabel = conf->flags.FlowLabel;
607	mgroup.flags.scope_mask = conf->flags.scope_mask;
608
609	/* override with user specified flags */
610	ret = parse_mgroup_flags(conf->p_log, &mgroup, p, lineno);
611
612	/* check/verify special IP group parameters */
613	if (mgid_is_ip(&mgroup.mgid)) {
614		ib_net16_t pkey = conf->p_prtn->pkey | cl_hton16(0x8000);
615
616		if (!ip_mgroup_pkey_ok(conf, &mgroup)
617		    || !ip_mgroup_rate_ok(conf, &mgroup)
618		    || !ip_mgroup_mtu_ok(conf, &mgroup))
619			goto error;
620
621		/* set special IP settings */
622		memcpy(&mgroup.mgid.raw[4], &pkey, sizeof(pkey));
623
624		if (mgroup.flags.Q_Key == 0)
625			mgroup.flags.Q_Key = OSM_IPOIB_BROADCAST_MGRP_QKEY;
626	}
627
628	/* don't create multiple copies of the group */
629	if (osm_get_mgrp_by_mgid(conf->p_subn, &mgroup.mgid))
630		goto error;
631
632	/* create the group */
633	__create_mgrp(conf, &mgroup);
634
635error:
636	return ret;
637}
638
639static struct part_conf *new_part_conf(osm_log_t * p_log, osm_subn_t * p_subn)
640{
641	static struct part_conf part;
642	struct part_conf *conf = &part;
643
644	memset(conf, 0, sizeof(*conf));
645	conf->p_log = p_log;
646	conf->p_subn = p_subn;
647	conf->p_prtn = NULL;
648	conf->is_ipoib = 0;
649	conf->flags.sl = OSM_DEFAULT_SL;
650	conf->flags.rate = OSM_DEFAULT_MGRP_RATE;
651	conf->flags.mtu = OSM_DEFAULT_MGRP_MTU;
652	conf->membership = LIMITED;
653	conf->indx0 = FALSE;
654	return conf;
655}
656
657static int flush_part_conf(struct part_conf *conf)
658{
659	memset(conf, 0, sizeof(*conf));
660	return 0;
661}
662
663static int parse_part_conf(struct part_conf *conf, char *str, int lineno)
664{
665	int ret, len = 0;
666	char *name, *id, *flag, *flval;
667	char *q, *p;
668
669	p = str;
670	if (*p == '\t' || *p == '\0' || *p == '\n')
671		p++;
672
673	len += (int)(p - str);
674	str = p;
675
676	if (conf->p_prtn)
677		goto skip_header;
678
679	q = strchr(p, ':');
680	if (!q) {
681		OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: "
682			"no partition definition found\n", lineno);
683		fprintf(stderr, "\nPARSE ERROR: line %d: "
684			"no partition definition found\n", lineno);
685		return -1;
686	}
687
688	*q++ = '\0';
689	str = q;
690
691	name = id = flag = flval = NULL;
692
693	q = strchr(p, ',');
694	if (q)
695		*q = '\0';
696
697	ret = parse_name_token(p, &name, &id);
698	p += ret;
699	len += ret;
700
701	while (q) {
702		flag = flval = NULL;
703		q = strchr(p, ',');
704		if (q)
705			*q++ = '\0';
706		ret = parse_name_token(p, &flag, &flval);
707		if (!flag) {
708			OSM_LOG(conf->p_log, OSM_LOG_ERROR,
709				"PARSE ERROR: line %d: "
710				"bad partition flags\n", lineno);
711			fprintf(stderr, "\nPARSE ERROR: line %d: "
712				"bad partition flags\n", lineno);
713			return -1;
714		}
715		p += ret;
716		len += ret;
717		partition_add_flag(lineno, conf, flag, flval);
718	}
719
720	if (p != str || (partition_create(lineno, conf,
721					  name, id, flag, flval) < 0)) {
722		OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: "
723			"bad partition definition\n", lineno);
724		fprintf(stderr, "\nPARSE ERROR: line %d: "
725			"bad partition definition\n", lineno);
726		return -1;
727	}
728
729skip_header:
730	do {
731		name = flag = NULL;
732		q = strchr(p, ',');
733		if (q)
734			*q++ = '\0';
735		ret = parse_name_token(p, &name, &flag);
736		len += ret;
737
738		if (strcmp(name, "mgid") == 0) {
739			/* parse an mgid line if specified. */
740			len += mgroup_create(p+ret, flag, lineno, conf);
741			goto done; /* We're done: this consumes the line */
742		}
743		if (partition_add_port(lineno, conf, name, flag) < 0) {
744			OSM_LOG(conf->p_log, OSM_LOG_ERROR,
745				"PARSE ERROR: line %d: "
746				"bad PortGUID\n", lineno);
747			fprintf(stderr, "PARSE ERROR: line %d: "
748				"bad PortGUID\n", lineno);
749			return -1;
750		}
751		p += ret;
752	} while (q);
753
754done:
755	return len;
756}
757
758/**
759 * @return 1 on error, 0 on success
760 */
761int osm_prtn_config_parse_file(osm_log_t * p_log, osm_subn_t * p_subn,
762			       const char *file_name)
763{
764	char line[4096];
765	struct part_conf *conf = NULL;
766	FILE *file;
767	int lineno;
768	int is_parse_success;
769
770	line[0] = '\0';
771	file = fopen(file_name, "r");
772	if (!file) {
773		OSM_LOG(p_log, OSM_LOG_VERBOSE,
774			"Cannot open config file \'%s\': %s\n",
775			file_name, strerror(errno));
776		return -1;
777	}
778
779	lineno = 0;
780
781	is_parse_success = 0;
782
783	while (fgets(line, sizeof(line) - 1, file) != NULL) {
784		char *q, *p = line;
785
786		lineno++;
787
788		p = line;
789
790		q = strchr(p, '#');
791		if (q)
792			*q = '\0';
793
794		do {
795			int len;
796			while (*p == ' ' || *p == '\t' || *p == '\n')
797				p++;
798			if (*p == '\0')
799				break;
800
801			if (!conf && !(conf = new_part_conf(p_log, p_subn))) {
802				OSM_LOG(p_log, OSM_LOG_ERROR,
803					"PARSE ERROR: line %d: "
804					"internal: cannot create config\n",
805					lineno);
806				fprintf(stderr,
807					"PARSE ERROR: line %d: "
808					"internal: cannot create config\n",
809					lineno);
810				is_parse_success = -1;
811				break;
812			}
813
814			q = strchr(p, ';');
815			if (q)
816				*q = '\0';
817
818			len = parse_part_conf(conf, p, lineno);
819			if (len < 0) {
820				is_parse_success = -1;
821				break;
822			}
823
824			is_parse_success = 1;
825
826			p += len;
827
828			if (q) {
829				flush_part_conf(conf);
830				conf = NULL;
831			}
832		} while (q);
833
834		if (is_parse_success == -1)
835			break;
836	}
837
838	fclose(file);
839
840	return (is_parse_success == 1) ? 0 : 1;
841}
842