1219820Sjeff/* 2219820Sjeff * Copyright (c) 2006-2007 Voltaire, Inc. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff/* 35219820Sjeff * Abstract: 36219820Sjeff * Implementation of opensm partition management configuration 37219820Sjeff */ 38219820Sjeff 39219820Sjeff#if HAVE_CONFIG_H 40219820Sjeff# include <config.h> 41219820Sjeff#endif /* HAVE_CONFIG_H */ 42219820Sjeff 43219820Sjeff#include <stdlib.h> 44219820Sjeff#include <stdio.h> 45219820Sjeff#include <string.h> 46219820Sjeff#include <errno.h> 47219820Sjeff#include <ctype.h> 48219820Sjeff 49219820Sjeff#include <iba/ib_types.h> 50219820Sjeff#include <opensm/osm_base.h> 51219820Sjeff#include <opensm/osm_partition.h> 52219820Sjeff#include <opensm/osm_subnet.h> 53219820Sjeff#include <opensm/osm_log.h> 54219820Sjeff 55219820Sjeff#include <complib/cl_byteswap.h> 56219820Sjeff 57219820Sjeffstruct part_conf { 58219820Sjeff osm_log_t *p_log; 59219820Sjeff osm_subn_t *p_subn; 60219820Sjeff osm_prtn_t *p_prtn; 61219820Sjeff unsigned is_ipoib, mtu, rate, sl, scope_mask; 62219820Sjeff boolean_t full; 63219820Sjeff}; 64219820Sjeff 65219820Sjeffextern osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn, 66219820Sjeff const char *name, uint16_t pkey); 67219820Sjeffextern ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, 68219820Sjeff osm_subn_t * p_subn, 69219820Sjeff osm_prtn_t * p, boolean_t full); 70219820Sjeffextern ib_api_status_t osm_prtn_add_port(osm_log_t * p_log, 71219820Sjeff osm_subn_t * p_subn, osm_prtn_t * p, 72219820Sjeff ib_net64_t guid, boolean_t full); 73219820Sjeffextern ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, 74219820Sjeff osm_subn_t * p_subn, osm_prtn_t * p, 75219820Sjeff uint8_t rate, 76219820Sjeff uint8_t mtu, uint8_t scope); 77219820Sjeff 78219820Sjeffstatic int partition_create(unsigned lineno, struct part_conf *conf, 79219820Sjeff char *name, char *id, char *flag, char *flag_val) 80219820Sjeff{ 81219820Sjeff uint16_t pkey; 82219820Sjeff unsigned int scope; 83219820Sjeff 84219820Sjeff if (!id && name && isdigit(*name)) { 85219820Sjeff id = name; 86219820Sjeff name = NULL; 87219820Sjeff } 88219820Sjeff 89219820Sjeff if (id) { 90219820Sjeff char *end; 91219820Sjeff 92219820Sjeff pkey = (uint16_t) strtoul(id, &end, 0); 93219820Sjeff if (end == id || *end) 94219820Sjeff return -1; 95219820Sjeff } else 96219820Sjeff pkey = 0; 97219820Sjeff 98219820Sjeff conf->p_prtn = osm_prtn_make_new(conf->p_log, conf->p_subn, 99219820Sjeff name, cl_hton16(pkey)); 100219820Sjeff if (!conf->p_prtn) 101219820Sjeff return -1; 102219820Sjeff 103219820Sjeff if (!conf->p_subn->opt.qos && conf->sl != OSM_DEFAULT_SL) { 104219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_DEBUG, "Overriding SL %d" 105219820Sjeff " to default SL %d on partition %s" 106219820Sjeff " as QoS is not enabled.\n", 107219820Sjeff conf->sl, OSM_DEFAULT_SL, name); 108219820Sjeff conf->sl = OSM_DEFAULT_SL; 109219820Sjeff } 110219820Sjeff conf->p_prtn->sl = (uint8_t) conf->sl; 111219820Sjeff 112219820Sjeff if (!conf->is_ipoib) 113219820Sjeff return 0; 114219820Sjeff 115219820Sjeff if (!conf->scope_mask) { 116219820Sjeff osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, 117219820Sjeff (uint8_t) conf->rate, 118219820Sjeff (uint8_t) conf->mtu, 119219820Sjeff 0); 120219820Sjeff return 0; 121219820Sjeff } 122219820Sjeff 123219820Sjeff for (scope = 0; scope < 16; scope++) { 124219820Sjeff if (((1<<scope) & conf->scope_mask) == 0) 125219820Sjeff continue; 126219820Sjeff 127219820Sjeff osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, 128219820Sjeff (uint8_t) conf->rate, 129219820Sjeff (uint8_t) conf->mtu, 130219820Sjeff (uint8_t) scope); 131219820Sjeff } 132219820Sjeff return 0; 133219820Sjeff} 134219820Sjeff 135219820Sjeffstatic int partition_add_flag(unsigned lineno, struct part_conf *conf, 136219820Sjeff char *flag, char *val) 137219820Sjeff{ 138219820Sjeff int len = strlen(flag); 139219820Sjeff if (!strncmp(flag, "ipoib", len)) { 140219820Sjeff conf->is_ipoib = 1; 141219820Sjeff } else if (!strncmp(flag, "mtu", len)) { 142219820Sjeff if (!val || (conf->mtu = strtoul(val, NULL, 0)) == 0) 143219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 144219820Sjeff "PARSE WARN: line %d: " 145219820Sjeff "flag \'mtu\' requires valid value" 146219820Sjeff " - skipped\n", lineno); 147219820Sjeff } else if (!strncmp(flag, "rate", len)) { 148219820Sjeff if (!val || (conf->rate = strtoul(val, NULL, 0)) == 0) 149219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 150219820Sjeff "PARSE WARN: line %d: " 151219820Sjeff "flag \'rate\' requires valid value" 152219820Sjeff " - skipped\n", lineno); 153219820Sjeff } else if (!strncmp(flag, "scope", len)) { 154219820Sjeff unsigned int scope; 155219820Sjeff if (!val || (scope = strtoul(val, NULL, 0)) == 0 || scope > 0xF) 156219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 157219820Sjeff "PARSE WARN: line %d: " 158219820Sjeff "flag \'scope\' requires valid value" 159219820Sjeff " - skipped\n", lineno); 160219820Sjeff else 161219820Sjeff conf->scope_mask |= (1<<scope); 162219820Sjeff } else if (!strncmp(flag, "sl", len)) { 163219820Sjeff unsigned sl; 164219820Sjeff char *end; 165219820Sjeff 166219820Sjeff if (!val || !*val || (sl = strtoul(val, &end, 0)) > 15 || 167219820Sjeff (*end && !isspace(*end))) 168219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 169219820Sjeff "PARSE WARN: line %d: " 170219820Sjeff "flag \'sl\' requires valid value" 171219820Sjeff " - skipped\n", lineno); 172219820Sjeff else 173219820Sjeff conf->sl = sl; 174219820Sjeff } else if (!strncmp(flag, "defmember", len)) { 175219820Sjeff if (!val || (strncmp(val, "limited", strlen(val)) 176219820Sjeff && strncmp(val, "full", strlen(val)))) 177219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 178219820Sjeff "PARSE WARN: line %d: " 179219820Sjeff "flag \'defmember\' requires valid value (limited or full)" 180219820Sjeff " - skipped\n", lineno); 181219820Sjeff else 182219820Sjeff conf->full = strncmp(val, "full", strlen(val)) == 0; 183219820Sjeff } else { 184219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 185219820Sjeff "PARSE WARN: line %d: " 186219820Sjeff "unrecognized partition flag \'%s\'" 187219820Sjeff " - ignored\n", lineno, flag); 188219820Sjeff } 189219820Sjeff return 0; 190219820Sjeff} 191219820Sjeff 192219820Sjeffstatic int partition_add_port(unsigned lineno, struct part_conf *conf, 193219820Sjeff char *name, char *flag) 194219820Sjeff{ 195219820Sjeff osm_prtn_t *p = conf->p_prtn; 196219820Sjeff ib_net64_t guid; 197219820Sjeff boolean_t full = conf->full; 198219820Sjeff 199219820Sjeff if (!name || !*name || !strncmp(name, "NONE", strlen(name))) 200219820Sjeff return 0; 201219820Sjeff 202219820Sjeff if (flag) { 203219820Sjeff /* reset default membership to limited */ 204219820Sjeff full = FALSE; 205219820Sjeff if (!strncmp(flag, "full", strlen(flag))) 206219820Sjeff full = TRUE; 207219820Sjeff else if (strncmp(flag, "limited", strlen(flag))) { 208219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 209219820Sjeff "PARSE WARN: line %d: " 210219820Sjeff "unrecognized port flag \'%s\'." 211219820Sjeff " Assume \'limited\'\n", lineno, flag); 212219820Sjeff } 213219820Sjeff } 214219820Sjeff 215219820Sjeff if (!strncmp(name, "ALL", strlen(name))) { 216219820Sjeff return osm_prtn_add_all(conf->p_log, conf->p_subn, p, 217219820Sjeff full) == IB_SUCCESS ? 0 : -1; 218219820Sjeff } else if (!strncmp(name, "SELF", strlen(name))) { 219219820Sjeff guid = cl_ntoh64(conf->p_subn->sm_port_guid); 220219820Sjeff } else { 221219820Sjeff char *end; 222219820Sjeff guid = strtoull(name, &end, 0); 223219820Sjeff if (!guid || *end) 224219820Sjeff return -1; 225219820Sjeff } 226219820Sjeff 227219820Sjeff if (osm_prtn_add_port(conf->p_log, conf->p_subn, p, 228219820Sjeff cl_hton64(guid), full) != IB_SUCCESS) 229219820Sjeff return -1; 230219820Sjeff 231219820Sjeff return 0; 232219820Sjeff} 233219820Sjeff 234219820Sjeff/* conf file parser */ 235219820Sjeff 236219820Sjeff#define STRIP_HEAD_SPACES(p) while (*(p) == ' ' || *(p) == '\t' || \ 237219820Sjeff *(p) == '\n') { (p)++; } 238219820Sjeff#define STRIP_TAIL_SPACES(p) { char *q = (p) + strlen(p); \ 239219820Sjeff while ( q != (p) && ( *q == '\0' || \ 240219820Sjeff *q == ' ' || *q == '\t' || \ 241219820Sjeff *q == '\n')) { *q-- = '\0'; }; } 242219820Sjeff 243219820Sjeffstatic int parse_name_token(char *str, char **name, char **val) 244219820Sjeff{ 245219820Sjeff int len = 0; 246219820Sjeff char *p, *q; 247219820Sjeff 248219820Sjeff *name = *val = NULL; 249219820Sjeff 250219820Sjeff p = str; 251219820Sjeff 252219820Sjeff while (*p == ' ' || *p == '\t' || *p == '\n') 253219820Sjeff p++; 254219820Sjeff 255219820Sjeff q = strchr(p, '='); 256219820Sjeff if (q) 257219820Sjeff *q++ = '\0'; 258219820Sjeff 259219820Sjeff len = strlen(str) + 1; 260219820Sjeff str = q; 261219820Sjeff 262219820Sjeff q = p + strlen(p); 263219820Sjeff while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n')) 264219820Sjeff *q-- = '\0'; 265219820Sjeff 266219820Sjeff *name = p; 267219820Sjeff 268219820Sjeff p = str; 269219820Sjeff if (!p) 270219820Sjeff return len; 271219820Sjeff 272219820Sjeff while (*p == ' ' || *p == '\t' || *p == '\n') 273219820Sjeff p++; 274219820Sjeff 275219820Sjeff q = p + strlen(p); 276219820Sjeff len += (int)(q - str) + 1; 277219820Sjeff while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n')) 278219820Sjeff *q-- = '\0'; 279219820Sjeff *val = p; 280219820Sjeff 281219820Sjeff return len; 282219820Sjeff} 283219820Sjeff 284219820Sjeffstatic struct part_conf *new_part_conf(osm_log_t * p_log, osm_subn_t * p_subn) 285219820Sjeff{ 286219820Sjeff static struct part_conf part; 287219820Sjeff struct part_conf *conf = ∂ 288219820Sjeff 289219820Sjeff memset(conf, 0, sizeof(*conf)); 290219820Sjeff conf->p_log = p_log; 291219820Sjeff conf->p_subn = p_subn; 292219820Sjeff conf->p_prtn = NULL; 293219820Sjeff conf->is_ipoib = 0; 294219820Sjeff conf->sl = OSM_DEFAULT_SL; 295219820Sjeff conf->full = FALSE; 296219820Sjeff return conf; 297219820Sjeff} 298219820Sjeff 299219820Sjeffstatic int flush_part_conf(struct part_conf *conf) 300219820Sjeff{ 301219820Sjeff memset(conf, 0, sizeof(*conf)); 302219820Sjeff return 0; 303219820Sjeff} 304219820Sjeff 305219820Sjeffstatic int parse_part_conf(struct part_conf *conf, char *str, int lineno) 306219820Sjeff{ 307219820Sjeff int ret, len = 0; 308219820Sjeff char *name, *id, *flag, *flval; 309219820Sjeff char *q, *p; 310219820Sjeff 311219820Sjeff p = str; 312219820Sjeff if (*p == '\t' || *p == '\0' || *p == '\n') 313219820Sjeff p++; 314219820Sjeff 315219820Sjeff len += (int)(p - str); 316219820Sjeff str = p; 317219820Sjeff 318219820Sjeff if (conf->p_prtn) 319219820Sjeff goto skip_header; 320219820Sjeff 321219820Sjeff q = strchr(p, ':'); 322219820Sjeff if (!q) { 323219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: " 324219820Sjeff "no partition definition found\n", lineno); 325219820Sjeff fprintf(stderr, "\nPARSE ERROR: line %d: " 326219820Sjeff "no partition definition found\n", lineno); 327219820Sjeff return -1; 328219820Sjeff } 329219820Sjeff 330219820Sjeff *q++ = '\0'; 331219820Sjeff str = q; 332219820Sjeff 333219820Sjeff name = id = flag = flval = NULL; 334219820Sjeff 335219820Sjeff q = strchr(p, ','); 336219820Sjeff if (q) 337219820Sjeff *q = '\0'; 338219820Sjeff 339219820Sjeff ret = parse_name_token(p, &name, &id); 340219820Sjeff p += ret; 341219820Sjeff len += ret; 342219820Sjeff 343219820Sjeff while (q) { 344219820Sjeff flag = flval = NULL; 345219820Sjeff q = strchr(p, ','); 346219820Sjeff if (q) 347219820Sjeff *q++ = '\0'; 348219820Sjeff ret = parse_name_token(p, &flag, &flval); 349219820Sjeff if (!flag) { 350219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_ERROR, 351219820Sjeff "PARSE ERROR: line %d: " 352219820Sjeff "bad partition flags\n", lineno); 353219820Sjeff fprintf(stderr, "\nPARSE ERROR: line %d: " 354219820Sjeff "bad partition flags\n", lineno); 355219820Sjeff return -1; 356219820Sjeff } 357219820Sjeff p += ret; 358219820Sjeff len += ret; 359219820Sjeff partition_add_flag(lineno, conf, flag, flval); 360219820Sjeff } 361219820Sjeff 362219820Sjeff if (p != str || (partition_create(lineno, conf, 363219820Sjeff name, id, flag, flval) < 0)) { 364219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: " 365219820Sjeff "bad partition definition\n", lineno); 366219820Sjeff fprintf(stderr, "\nPARSE ERROR: line %d: " 367219820Sjeff "bad partition definition\n", lineno); 368219820Sjeff return -1; 369219820Sjeff } 370219820Sjeff 371219820Sjeffskip_header: 372219820Sjeff do { 373219820Sjeff name = flag = NULL; 374219820Sjeff q = strchr(p, ','); 375219820Sjeff if (q) 376219820Sjeff *q++ = '\0'; 377219820Sjeff ret = parse_name_token(p, &name, &flag); 378219820Sjeff if (partition_add_port(lineno, conf, name, flag) < 0) { 379219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_ERROR, 380219820Sjeff "PARSE ERROR: line %d: " 381219820Sjeff "bad PortGUID\n", lineno); 382219820Sjeff fprintf(stderr, "PARSE ERROR: line %d: " 383219820Sjeff "bad PortGUID\n", lineno); 384219820Sjeff return -1; 385219820Sjeff } 386219820Sjeff p += ret; 387219820Sjeff len += ret; 388219820Sjeff } while (q); 389219820Sjeff 390219820Sjeff return len; 391219820Sjeff} 392219820Sjeff 393219820Sjeffint osm_prtn_config_parse_file(osm_log_t * p_log, osm_subn_t * p_subn, 394219820Sjeff const char *file_name) 395219820Sjeff{ 396219820Sjeff char line[1024]; 397219820Sjeff struct part_conf *conf = NULL; 398219820Sjeff FILE *file; 399219820Sjeff int lineno; 400219820Sjeff 401219820Sjeff file = fopen(file_name, "r"); 402219820Sjeff if (!file) { 403219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 404219820Sjeff "Cannot open config file \'%s\': %s\n", 405219820Sjeff file_name, strerror(errno)); 406219820Sjeff return -1; 407219820Sjeff } 408219820Sjeff 409219820Sjeff lineno = 0; 410219820Sjeff 411219820Sjeff while (fgets(line, sizeof(line) - 1, file) != NULL) { 412219820Sjeff char *q, *p = line; 413219820Sjeff 414219820Sjeff lineno++; 415219820Sjeff 416219820Sjeff p = line; 417219820Sjeff 418219820Sjeff q = strchr(p, '#'); 419219820Sjeff if (q) 420219820Sjeff *q = '\0'; 421219820Sjeff 422219820Sjeff do { 423219820Sjeff int len; 424219820Sjeff while (*p == ' ' || *p == '\t' || *p == '\n') 425219820Sjeff p++; 426219820Sjeff if (*p == '\0') 427219820Sjeff break; 428219820Sjeff 429219820Sjeff if (!conf && !(conf = new_part_conf(p_log, p_subn))) { 430219820Sjeff OSM_LOG(conf->p_log, OSM_LOG_ERROR, 431219820Sjeff "PARSE ERROR: line %d: " 432219820Sjeff "internal: cannot create config\n", 433219820Sjeff lineno); 434219820Sjeff fprintf(stderr, 435219820Sjeff "PARSE ERROR: line %d: " 436219820Sjeff "internal: cannot create config\n", 437219820Sjeff lineno); 438219820Sjeff break; 439219820Sjeff } 440219820Sjeff 441219820Sjeff q = strchr(p, ';'); 442219820Sjeff if (q) 443219820Sjeff *q = '\0'; 444219820Sjeff 445219820Sjeff len = parse_part_conf(conf, p, lineno); 446219820Sjeff if (len < 0) { 447219820Sjeff break; 448219820Sjeff } 449219820Sjeff 450219820Sjeff p += len; 451219820Sjeff 452219820Sjeff if (q) { 453219820Sjeff flush_part_conf(conf); 454219820Sjeff conf = NULL; 455219820Sjeff } 456219820Sjeff } while (q); 457219820Sjeff } 458219820Sjeff 459219820Sjeff fclose(file); 460219820Sjeff 461219820Sjeff return 0; 462219820Sjeff} 463