1/* 2 * Copyright (c) 2006-2007 Voltaire, Inc. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 */ 33 34/* 35 * Abstract: 36 * Implementation of opensm partition management configuration 37 */ 38 39#if HAVE_CONFIG_H 40# include <config.h> 41#endif /* HAVE_CONFIG_H */ 42 43#include <stdlib.h> 44#include <stdio.h> 45#include <string.h> 46#include <errno.h> 47#include <ctype.h> 48 49#include <iba/ib_types.h> 50#include <opensm/osm_base.h> 51#include <opensm/osm_partition.h> 52#include <opensm/osm_subnet.h> 53#include <opensm/osm_log.h> 54 55#include <complib/cl_byteswap.h> 56 57struct part_conf { 58 osm_log_t *p_log; 59 osm_subn_t *p_subn; 60 osm_prtn_t *p_prtn; 61 unsigned is_ipoib, mtu, rate, sl, scope_mask; 62 boolean_t full; 63}; 64 65extern osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn, 66 const char *name, uint16_t pkey); 67extern ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, 68 osm_subn_t * p_subn, 69 osm_prtn_t * p, boolean_t full); 70extern ib_api_status_t osm_prtn_add_port(osm_log_t * p_log, 71 osm_subn_t * p_subn, osm_prtn_t * p, 72 ib_net64_t guid, boolean_t full); 73extern ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, 74 osm_subn_t * p_subn, osm_prtn_t * p, 75 uint8_t rate, 76 uint8_t mtu, uint8_t scope); 77 78static int partition_create(unsigned lineno, struct part_conf *conf, 79 char *name, char *id, char *flag, char *flag_val) 80{ 81 uint16_t pkey; 82 unsigned int scope; 83 84 if (!id && name && isdigit(*name)) { 85 id = name; 86 name = NULL; 87 } 88 89 if (id) { 90 char *end; 91 92 pkey = (uint16_t) strtoul(id, &end, 0); 93 if (end == id || *end) 94 return -1; 95 } else 96 pkey = 0; 97 98 conf->p_prtn = osm_prtn_make_new(conf->p_log, conf->p_subn, 99 name, cl_hton16(pkey)); 100 if (!conf->p_prtn) 101 return -1; 102 103 if (!conf->p_subn->opt.qos && conf->sl != OSM_DEFAULT_SL) { 104 OSM_LOG(conf->p_log, OSM_LOG_DEBUG, "Overriding SL %d" 105 " to default SL %d on partition %s" 106 " as QoS is not enabled.\n", 107 conf->sl, OSM_DEFAULT_SL, name); 108 conf->sl = OSM_DEFAULT_SL; 109 } 110 conf->p_prtn->sl = (uint8_t) conf->sl; 111 112 if (!conf->is_ipoib) 113 return 0; 114 115 if (!conf->scope_mask) { 116 osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, 117 (uint8_t) conf->rate, 118 (uint8_t) conf->mtu, 119 0); 120 return 0; 121 } 122 123 for (scope = 0; scope < 16; scope++) { 124 if (((1<<scope) & conf->scope_mask) == 0) 125 continue; 126 127 osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, 128 (uint8_t) conf->rate, 129 (uint8_t) conf->mtu, 130 (uint8_t) scope); 131 } 132 return 0; 133} 134 135static int partition_add_flag(unsigned lineno, struct part_conf *conf, 136 char *flag, char *val) 137{ 138 int len = strlen(flag); 139 if (!strncmp(flag, "ipoib", len)) { 140 conf->is_ipoib = 1; 141 } else if (!strncmp(flag, "mtu", len)) { 142 if (!val || (conf->mtu = strtoul(val, NULL, 0)) == 0) 143 OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 144 "PARSE WARN: line %d: " 145 "flag \'mtu\' requires valid value" 146 " - skipped\n", lineno); 147 } else if (!strncmp(flag, "rate", len)) { 148 if (!val || (conf->rate = strtoul(val, NULL, 0)) == 0) 149 OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 150 "PARSE WARN: line %d: " 151 "flag \'rate\' requires valid value" 152 " - skipped\n", lineno); 153 } else if (!strncmp(flag, "scope", len)) { 154 unsigned int scope; 155 if (!val || (scope = strtoul(val, NULL, 0)) == 0 || scope > 0xF) 156 OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 157 "PARSE WARN: line %d: " 158 "flag \'scope\' requires valid value" 159 " - skipped\n", lineno); 160 else 161 conf->scope_mask |= (1<<scope); 162 } else if (!strncmp(flag, "sl", len)) { 163 unsigned sl; 164 char *end; 165 166 if (!val || !*val || (sl = strtoul(val, &end, 0)) > 15 || 167 (*end && !isspace(*end))) 168 OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 169 "PARSE WARN: line %d: " 170 "flag \'sl\' requires valid value" 171 " - skipped\n", lineno); 172 else 173 conf->sl = sl; 174 } else if (!strncmp(flag, "defmember", len)) { 175 if (!val || (strncmp(val, "limited", strlen(val)) 176 && strncmp(val, "full", strlen(val)))) 177 OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 178 "PARSE WARN: line %d: " 179 "flag \'defmember\' requires valid value (limited or full)" 180 " - skipped\n", lineno); 181 else 182 conf->full = strncmp(val, "full", strlen(val)) == 0; 183 } else { 184 OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 185 "PARSE WARN: line %d: " 186 "unrecognized partition flag \'%s\'" 187 " - ignored\n", lineno, flag); 188 } 189 return 0; 190} 191 192static int partition_add_port(unsigned lineno, struct part_conf *conf, 193 char *name, char *flag) 194{ 195 osm_prtn_t *p = conf->p_prtn; 196 ib_net64_t guid; 197 boolean_t full = conf->full; 198 199 if (!name || !*name || !strncmp(name, "NONE", strlen(name))) 200 return 0; 201 202 if (flag) { 203 /* reset default membership to limited */ 204 full = FALSE; 205 if (!strncmp(flag, "full", strlen(flag))) 206 full = TRUE; 207 else if (strncmp(flag, "limited", strlen(flag))) { 208 OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, 209 "PARSE WARN: line %d: " 210 "unrecognized port flag \'%s\'." 211 " Assume \'limited\'\n", lineno, flag); 212 } 213 } 214 215 if (!strncmp(name, "ALL", strlen(name))) { 216 return osm_prtn_add_all(conf->p_log, conf->p_subn, p, 217 full) == IB_SUCCESS ? 0 : -1; 218 } else if (!strncmp(name, "SELF", strlen(name))) { 219 guid = cl_ntoh64(conf->p_subn->sm_port_guid); 220 } else { 221 char *end; 222 guid = strtoull(name, &end, 0); 223 if (!guid || *end) 224 return -1; 225 } 226 227 if (osm_prtn_add_port(conf->p_log, conf->p_subn, p, 228 cl_hton64(guid), full) != IB_SUCCESS) 229 return -1; 230 231 return 0; 232} 233 234/* conf file parser */ 235 236#define STRIP_HEAD_SPACES(p) while (*(p) == ' ' || *(p) == '\t' || \ 237 *(p) == '\n') { (p)++; } 238#define STRIP_TAIL_SPACES(p) { char *q = (p) + strlen(p); \ 239 while ( q != (p) && ( *q == '\0' || \ 240 *q == ' ' || *q == '\t' || \ 241 *q == '\n')) { *q-- = '\0'; }; } 242 243static int parse_name_token(char *str, char **name, char **val) 244{ 245 int len = 0; 246 char *p, *q; 247 248 *name = *val = NULL; 249 250 p = str; 251 252 while (*p == ' ' || *p == '\t' || *p == '\n') 253 p++; 254 255 q = strchr(p, '='); 256 if (q) 257 *q++ = '\0'; 258 259 len = strlen(str) + 1; 260 str = q; 261 262 q = p + strlen(p); 263 while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n')) 264 *q-- = '\0'; 265 266 *name = p; 267 268 p = str; 269 if (!p) 270 return len; 271 272 while (*p == ' ' || *p == '\t' || *p == '\n') 273 p++; 274 275 q = p + strlen(p); 276 len += (int)(q - str) + 1; 277 while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n')) 278 *q-- = '\0'; 279 *val = p; 280 281 return len; 282} 283 284static struct part_conf *new_part_conf(osm_log_t * p_log, osm_subn_t * p_subn) 285{ 286 static struct part_conf part; 287 struct part_conf *conf = ∂ 288 289 memset(conf, 0, sizeof(*conf)); 290 conf->p_log = p_log; 291 conf->p_subn = p_subn; 292 conf->p_prtn = NULL; 293 conf->is_ipoib = 0; 294 conf->sl = OSM_DEFAULT_SL; 295 conf->full = FALSE; 296 return conf; 297} 298 299static int flush_part_conf(struct part_conf *conf) 300{ 301 memset(conf, 0, sizeof(*conf)); 302 return 0; 303} 304 305static int parse_part_conf(struct part_conf *conf, char *str, int lineno) 306{ 307 int ret, len = 0; 308 char *name, *id, *flag, *flval; 309 char *q, *p; 310 311 p = str; 312 if (*p == '\t' || *p == '\0' || *p == '\n') 313 p++; 314 315 len += (int)(p - str); 316 str = p; 317 318 if (conf->p_prtn) 319 goto skip_header; 320 321 q = strchr(p, ':'); 322 if (!q) { 323 OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: " 324 "no partition definition found\n", lineno); 325 fprintf(stderr, "\nPARSE ERROR: line %d: " 326 "no partition definition found\n", lineno); 327 return -1; 328 } 329 330 *q++ = '\0'; 331 str = q; 332 333 name = id = flag = flval = NULL; 334 335 q = strchr(p, ','); 336 if (q) 337 *q = '\0'; 338 339 ret = parse_name_token(p, &name, &id); 340 p += ret; 341 len += ret; 342 343 while (q) { 344 flag = flval = NULL; 345 q = strchr(p, ','); 346 if (q) 347 *q++ = '\0'; 348 ret = parse_name_token(p, &flag, &flval); 349 if (!flag) { 350 OSM_LOG(conf->p_log, OSM_LOG_ERROR, 351 "PARSE ERROR: line %d: " 352 "bad partition flags\n", lineno); 353 fprintf(stderr, "\nPARSE ERROR: line %d: " 354 "bad partition flags\n", lineno); 355 return -1; 356 } 357 p += ret; 358 len += ret; 359 partition_add_flag(lineno, conf, flag, flval); 360 } 361 362 if (p != str || (partition_create(lineno, conf, 363 name, id, flag, flval) < 0)) { 364 OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: " 365 "bad partition definition\n", lineno); 366 fprintf(stderr, "\nPARSE ERROR: line %d: " 367 "bad partition definition\n", lineno); 368 return -1; 369 } 370 371skip_header: 372 do { 373 name = flag = NULL; 374 q = strchr(p, ','); 375 if (q) 376 *q++ = '\0'; 377 ret = parse_name_token(p, &name, &flag); 378 if (partition_add_port(lineno, conf, name, flag) < 0) { 379 OSM_LOG(conf->p_log, OSM_LOG_ERROR, 380 "PARSE ERROR: line %d: " 381 "bad PortGUID\n", lineno); 382 fprintf(stderr, "PARSE ERROR: line %d: " 383 "bad PortGUID\n", lineno); 384 return -1; 385 } 386 p += ret; 387 len += ret; 388 } while (q); 389 390 return len; 391} 392 393int osm_prtn_config_parse_file(osm_log_t * p_log, osm_subn_t * p_subn, 394 const char *file_name) 395{ 396 char line[1024]; 397 struct part_conf *conf = NULL; 398 FILE *file; 399 int lineno; 400 401 file = fopen(file_name, "r"); 402 if (!file) { 403 OSM_LOG(p_log, OSM_LOG_VERBOSE, 404 "Cannot open config file \'%s\': %s\n", 405 file_name, strerror(errno)); 406 return -1; 407 } 408 409 lineno = 0; 410 411 while (fgets(line, sizeof(line) - 1, file) != NULL) { 412 char *q, *p = line; 413 414 lineno++; 415 416 p = line; 417 418 q = strchr(p, '#'); 419 if (q) 420 *q = '\0'; 421 422 do { 423 int len; 424 while (*p == ' ' || *p == '\t' || *p == '\n') 425 p++; 426 if (*p == '\0') 427 break; 428 429 if (!conf && !(conf = new_part_conf(p_log, p_subn))) { 430 OSM_LOG(conf->p_log, OSM_LOG_ERROR, 431 "PARSE ERROR: line %d: " 432 "internal: cannot create config\n", 433 lineno); 434 fprintf(stderr, 435 "PARSE ERROR: line %d: " 436 "internal: cannot create config\n", 437 lineno); 438 break; 439 } 440 441 q = strchr(p, ';'); 442 if (q) 443 *q = '\0'; 444 445 len = parse_part_conf(conf, p, lineno); 446 if (len < 0) { 447 break; 448 } 449 450 p += len; 451 452 if (q) { 453 flush_part_conf(conf); 454 conf = NULL; 455 } 456 } while (q); 457 } 458 459 fclose(file); 460 461 return 0; 462} 463