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
60 typedef enum {
61 LIMITED,
62 FULL,
63 BOTH
64 } membership_t;
65
66 const 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
77 struct group_flags {
78 unsigned mtu, rate, sl, scope_mask;
79 uint32_t Q_Key;
80 uint8_t TClass;
81 uint32_t FlowLabel;
82 };
83
84 struct precreate_mgroup {
85 ib_gid_t mgid;
86 struct group_flags flags;
87 };
88
89 struct 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
99 extern osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn,
100 const char *name, uint16_t pkey);
101 extern 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);
104 extern 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
109 ib_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
mgid_is_broadcast(const ib_gid_t * mgid)116 static 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
mgid_is_ip(const ib_gid_t * mgid)122 static 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
ip_mgroup_pkey_ok(struct part_conf * conf,struct precreate_mgroup * group)128 static 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
ip_mgroup_rate_ok(struct part_conf * conf,struct precreate_mgroup * group)149 static 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
ip_mgroup_mtu_ok(struct part_conf * conf,struct precreate_mgroup * group)167 static 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
__create_mgrp(struct part_conf * conf,struct precreate_mgroup * group)185 static 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
partition_create(unsigned lineno,struct part_conf * conf,char * name,char * id,char * flag,char * flag_val)217 static 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_ */
parse_group_flag(unsigned lineno,osm_log_t * p_log,struct group_flags * flags,char * flag,char * val)271 static 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
partition_add_flag(unsigned lineno,struct part_conf * conf,char * flag,char * val)347 static 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 }
manage_membership_change(struct part_conf * conf,osm_prtn_t * p,unsigned type,membership_t membership,ib_net64_t guid)385 static 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 }
partition_add_all(struct part_conf * conf,osm_prtn_t * p,unsigned type,membership_t membership)436 static 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
partition_add_port(unsigned lineno,struct part_conf * conf,char * name,char * flag)451 static 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
parse_name_token(char * str,char ** name,char ** val)517 static 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
parse_mgroup_flags(osm_log_t * p_log,struct precreate_mgroup * mgroup,char * p,unsigned lineno)558 static 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
mgroup_create(char * p,char * mgid,unsigned lineno,struct part_conf * conf)586 static 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
635 error:
636 return ret;
637 }
638
new_part_conf(osm_log_t * p_log,osm_subn_t * p_subn)639 static 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 = ∂
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
flush_part_conf(struct part_conf * conf)657 static int flush_part_conf(struct part_conf *conf)
658 {
659 memset(conf, 0, sizeof(*conf));
660 return 0;
661 }
662
parse_part_conf(struct part_conf * conf,char * str,int lineno)663 static 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
729 skip_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
754 done:
755 return len;
756 }
757
758 /**
759 * @return 1 on error, 0 on success
760 */
osm_prtn_config_parse_file(osm_log_t * p_log,osm_subn_t * p_subn,const char * file_name)761 int 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