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 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 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 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 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 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 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 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_ */ 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 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 } 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 } 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 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 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 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 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 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 657 static int flush_part_conf(struct part_conf *conf) 658 { 659 memset(conf, 0, sizeof(*conf)); 660 return 0; 661 } 662 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 */ 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