1/* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. 4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5 * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. 6 * 7 * This software is available to you under a choice of one of two 8 * licenses. You may choose to be licensed under the terms of the GNU 9 * General Public License (GPL) Version 2, available from the file 10 * COPYING in the main directory of this source tree, or the 11 * OpenIB.org BSD license below: 12 * 13 * Redistribution and use in source and binary forms, with or 14 * without modification, are permitted provided that the following 15 * conditions are met: 16 * 17 * - Redistributions of source code must retain the above 18 * copyright notice, this list of conditions and the following 19 * disclaimer. 20 * 21 * - Redistributions in binary form must reproduce the above 22 * copyright notice, this list of conditions and the following 23 * disclaimer in the documentation and/or other materials 24 * provided with the distribution. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 * SOFTWARE. 34 * 35 */ 36 37/* 38 * Abstract: 39 * Implementation of osm_subn_t. 40 * This object represents an IBA subnet. 41 * This object is part of the opensm family of objects. 42 */ 43 44#if HAVE_CONFIG_H 45# include <config.h> 46#endif /* HAVE_CONFIG_H */ 47 48#include <string.h> 49#include <stdio.h> 50#include <stdarg.h> 51#include <limits.h> 52#include <errno.h> 53#include <ctype.h> 54#include <complib/cl_debug.h> 55#include <complib/cl_log.h> 56#include <opensm/osm_subnet.h> 57#include <opensm/osm_opensm.h> 58#include <opensm/osm_log.h> 59#include <opensm/osm_madw.h> 60#include <opensm/osm_port.h> 61#include <opensm/osm_switch.h> 62#include <opensm/osm_remote_sm.h> 63#include <opensm/osm_partition.h> 64#include <opensm/osm_node.h> 65#include <opensm/osm_multicast.h> 66#include <opensm/osm_inform.h> 67#include <opensm/osm_console.h> 68#include <opensm/osm_perfmgr.h> 69#include <opensm/osm_event_plugin.h> 70#include <opensm/osm_qos_policy.h> 71 72static const char null_str[] = "(null)"; 73 74/********************************************************************** 75 **********************************************************************/ 76void osm_subn_construct(IN osm_subn_t * const p_subn) 77{ 78 memset(p_subn, 0, sizeof(*p_subn)); 79 cl_ptr_vector_construct(&p_subn->port_lid_tbl); 80 cl_qmap_init(&p_subn->sw_guid_tbl); 81 cl_qmap_init(&p_subn->node_guid_tbl); 82 cl_qmap_init(&p_subn->port_guid_tbl); 83 cl_qmap_init(&p_subn->sm_guid_tbl); 84 cl_qlist_init(&p_subn->sa_sr_list); 85 cl_qlist_init(&p_subn->sa_infr_list); 86 cl_qlist_init(&p_subn->prefix_routes_list); 87 cl_qmap_init(&p_subn->rtr_guid_tbl); 88 cl_qmap_init(&p_subn->prtn_pkey_tbl); 89} 90 91/********************************************************************** 92 **********************************************************************/ 93void osm_subn_destroy(IN osm_subn_t * const p_subn) 94{ 95 int i; 96 osm_node_t *p_node, *p_next_node; 97 osm_port_t *p_port, *p_next_port; 98 osm_switch_t *p_sw, *p_next_sw; 99 osm_remote_sm_t *p_rsm, *p_next_rsm; 100 osm_prtn_t *p_prtn, *p_next_prtn; 101 osm_mgrp_t *p_mgrp; 102 osm_infr_t *p_infr, *p_next_infr; 103 104 /* it might be a good idea to de-allocate all known objects */ 105 p_next_node = (osm_node_t *) cl_qmap_head(&p_subn->node_guid_tbl); 106 while (p_next_node != 107 (osm_node_t *) cl_qmap_end(&p_subn->node_guid_tbl)) { 108 p_node = p_next_node; 109 p_next_node = (osm_node_t *) cl_qmap_next(&p_node->map_item); 110 osm_node_delete(&p_node); 111 } 112 113 p_next_port = (osm_port_t *) cl_qmap_head(&p_subn->port_guid_tbl); 114 while (p_next_port != 115 (osm_port_t *) cl_qmap_end(&p_subn->port_guid_tbl)) { 116 p_port = p_next_port; 117 p_next_port = (osm_port_t *) cl_qmap_next(&p_port->map_item); 118 osm_port_delete(&p_port); 119 } 120 121 p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); 122 while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { 123 p_sw = p_next_sw; 124 p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); 125 osm_switch_delete(&p_sw); 126 } 127 128 p_next_rsm = (osm_remote_sm_t *) cl_qmap_head(&p_subn->sm_guid_tbl); 129 while (p_next_rsm != 130 (osm_remote_sm_t *) cl_qmap_end(&p_subn->sm_guid_tbl)) { 131 p_rsm = p_next_rsm; 132 p_next_rsm = (osm_remote_sm_t *) cl_qmap_next(&p_rsm->map_item); 133 free(p_rsm); 134 } 135 136 p_next_prtn = (osm_prtn_t *) cl_qmap_head(&p_subn->prtn_pkey_tbl); 137 while (p_next_prtn != 138 (osm_prtn_t *) cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 139 p_prtn = p_next_prtn; 140 p_next_prtn = (osm_prtn_t *) cl_qmap_next(&p_prtn->map_item); 141 osm_prtn_delete(&p_prtn); 142 } 143 144 for (i = 0; i <= p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; 145 i++) { 146 p_mgrp = p_subn->mgroups[i]; 147 p_subn->mgroups[i] = NULL; 148 if (p_mgrp) 149 osm_mgrp_delete(p_mgrp); 150 } 151 152 p_next_infr = (osm_infr_t *) cl_qlist_head(&p_subn->sa_infr_list); 153 while (p_next_infr != 154 (osm_infr_t *) cl_qlist_end(&p_subn->sa_infr_list)) { 155 p_infr = p_next_infr; 156 p_next_infr = (osm_infr_t *) cl_qlist_next(&p_infr->list_item); 157 osm_infr_delete(p_infr); 158 } 159 160 cl_ptr_vector_destroy(&p_subn->port_lid_tbl); 161 162 osm_qos_policy_destroy(p_subn->p_qos_policy); 163 164 while (!cl_is_qlist_empty(&p_subn->prefix_routes_list)) { 165 cl_list_item_t *item = cl_qlist_remove_head(&p_subn->prefix_routes_list); 166 free(item); 167 } 168} 169 170/********************************************************************** 171 **********************************************************************/ 172ib_api_status_t 173osm_subn_init(IN osm_subn_t * const p_subn, 174 IN osm_opensm_t * const p_osm, 175 IN const osm_subn_opt_t * const p_opt) 176{ 177 cl_status_t status; 178 179 p_subn->p_osm = p_osm; 180 181 status = cl_ptr_vector_init(&p_subn->port_lid_tbl, 182 OSM_SUBNET_VECTOR_MIN_SIZE, 183 OSM_SUBNET_VECTOR_GROW_SIZE); 184 if (status != CL_SUCCESS) 185 return (status); 186 187 status = cl_ptr_vector_set_capacity(&p_subn->port_lid_tbl, 188 OSM_SUBNET_VECTOR_CAPACITY); 189 if (status != CL_SUCCESS) 190 return (status); 191 192 /* 193 LID zero is not valid. NULL out this entry for the 194 convenience of other code. 195 */ 196 cl_ptr_vector_set(&p_subn->port_lid_tbl, 0, NULL); 197 198 p_subn->opt = *p_opt; 199 p_subn->max_ucast_lid_ho = IB_LID_UCAST_END_HO; 200 p_subn->max_mcast_lid_ho = IB_LID_MCAST_END_HO; 201 p_subn->min_ca_mtu = IB_MAX_MTU; 202 p_subn->min_ca_rate = IB_MAX_RATE; 203 p_subn->ignore_existing_lfts = TRUE; 204 205 /* we assume master by default - so we only need to set it true if STANDBY */ 206 p_subn->coming_out_of_standby = FALSE; 207 208 return (IB_SUCCESS); 209} 210 211/********************************************************************** 212 **********************************************************************/ 213ib_api_status_t 214osm_get_gid_by_mad_addr(IN osm_log_t * p_log, 215 IN const osm_subn_t * p_subn, 216 IN const osm_mad_addr_t * p_mad_addr, 217 OUT ib_gid_t * p_gid) 218{ 219 const cl_ptr_vector_t *p_tbl; 220 const osm_port_t *p_port = NULL; 221 222 if (p_gid == NULL) { 223 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7505: " 224 "Provided output GID is NULL\n"); 225 return (IB_INVALID_PARAMETER); 226 } 227 228 /* Find the port gid of the request in the subnet */ 229 p_tbl = &p_subn->port_lid_tbl; 230 231 CL_ASSERT(cl_ptr_vector_get_size(p_tbl) < 0x10000); 232 233 if ((uint16_t) cl_ptr_vector_get_size(p_tbl) > 234 cl_ntoh16(p_mad_addr->dest_lid)) { 235 p_port = 236 cl_ptr_vector_get(p_tbl, cl_ntoh16(p_mad_addr->dest_lid)); 237 if (p_port == NULL) { 238 OSM_LOG(p_log, OSM_LOG_DEBUG, 239 "Did not find any port with LID: %u\n", 240 cl_ntoh16(p_mad_addr->dest_lid)); 241 return (IB_INVALID_PARAMETER); 242 } 243 p_gid->unicast.interface_id = p_port->p_physp->port_guid; 244 p_gid->unicast.prefix = p_subn->opt.subnet_prefix; 245 } else { 246 /* The dest_lid is not in the subnet table - this is an error */ 247 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7501: " 248 "LID is out of range: %u\n", 249 cl_ntoh16(p_mad_addr->dest_lid)); 250 return (IB_INVALID_PARAMETER); 251 } 252 253 return (IB_SUCCESS); 254} 255 256/********************************************************************** 257 **********************************************************************/ 258osm_physp_t *osm_get_physp_by_mad_addr(IN osm_log_t * p_log, 259 IN const osm_subn_t * p_subn, 260 IN osm_mad_addr_t * p_mad_addr) 261{ 262 const cl_ptr_vector_t *p_port_lid_tbl; 263 osm_port_t *p_port = NULL; 264 osm_physp_t *p_physp = NULL; 265 266 /* Find the port gid of the request in the subnet */ 267 p_port_lid_tbl = &p_subn->port_lid_tbl; 268 269 CL_ASSERT(cl_ptr_vector_get_size(p_port_lid_tbl) < 0x10000); 270 271 if ((uint16_t) cl_ptr_vector_get_size(p_port_lid_tbl) > 272 cl_ntoh16(p_mad_addr->dest_lid)) { 273 p_port = 274 cl_ptr_vector_get(p_port_lid_tbl, 275 cl_ntoh16(p_mad_addr->dest_lid)); 276 if (p_port == NULL) { 277 /* The port is not in the port_lid table - this is an error */ 278 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7502: " 279 "Cannot locate port object by lid: %u\n", 280 cl_ntoh16(p_mad_addr->dest_lid)); 281 282 goto Exit; 283 } 284 p_physp = p_port->p_physp; 285 } else { 286 /* The dest_lid is not in the subnet table - this is an error */ 287 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7503: " 288 "Lid is out of range: %u\n", 289 cl_ntoh16(p_mad_addr->dest_lid)); 290 } 291 292Exit: 293 return p_physp; 294} 295 296/********************************************************************** 297 **********************************************************************/ 298osm_port_t *osm_get_port_by_mad_addr(IN osm_log_t * p_log, 299 IN const osm_subn_t * p_subn, 300 IN osm_mad_addr_t * p_mad_addr) 301{ 302 const cl_ptr_vector_t *p_port_lid_tbl; 303 osm_port_t *p_port = NULL; 304 305 /* Find the port gid of the request in the subnet */ 306 p_port_lid_tbl = &p_subn->port_lid_tbl; 307 308 CL_ASSERT(cl_ptr_vector_get_size(p_port_lid_tbl) < 0x10000); 309 310 if ((uint16_t) cl_ptr_vector_get_size(p_port_lid_tbl) > 311 cl_ntoh16(p_mad_addr->dest_lid)) { 312 p_port = 313 cl_ptr_vector_get(p_port_lid_tbl, 314 cl_ntoh16(p_mad_addr->dest_lid)); 315 } else { 316 /* The dest_lid is not in the subnet table - this is an error */ 317 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7504: " 318 "Lid is out of range: %u\n", 319 cl_ntoh16(p_mad_addr->dest_lid)); 320 } 321 322 return p_port; 323} 324 325/********************************************************************** 326 **********************************************************************/ 327osm_switch_t *osm_get_switch_by_guid(IN const osm_subn_t * p_subn, 328 IN uint64_t guid) 329{ 330 osm_switch_t *p_switch; 331 332 p_switch = (osm_switch_t *) cl_qmap_get(&(p_subn->sw_guid_tbl), guid); 333 if (p_switch == (osm_switch_t *) cl_qmap_end(&(p_subn->sw_guid_tbl))) 334 p_switch = NULL; 335 return p_switch; 336} 337 338/********************************************************************** 339 **********************************************************************/ 340osm_node_t *osm_get_node_by_guid(IN osm_subn_t const *p_subn, IN uint64_t guid) 341{ 342 osm_node_t *p_node; 343 344 p_node = (osm_node_t *) cl_qmap_get(&(p_subn->node_guid_tbl), guid); 345 if (p_node == (osm_node_t *) cl_qmap_end(&(p_subn->node_guid_tbl))) 346 p_node = NULL; 347 return p_node; 348} 349 350/********************************************************************** 351 **********************************************************************/ 352osm_port_t *osm_get_port_by_guid(IN osm_subn_t const *p_subn, IN ib_net64_t guid) 353{ 354 osm_port_t *p_port; 355 356 p_port = (osm_port_t *) cl_qmap_get(&(p_subn->port_guid_tbl), guid); 357 if (p_port == (osm_port_t *) cl_qmap_end(&(p_subn->port_guid_tbl))) 358 p_port = NULL; 359 return p_port; 360} 361 362/********************************************************************** 363 **********************************************************************/ 364static void subn_set_default_qos_options(IN osm_qos_options_t * opt) 365{ 366 opt->max_vls = OSM_DEFAULT_QOS_MAX_VLS; 367 opt->high_limit = OSM_DEFAULT_QOS_HIGH_LIMIT; 368 opt->vlarb_high = OSM_DEFAULT_QOS_VLARB_HIGH; 369 opt->vlarb_low = OSM_DEFAULT_QOS_VLARB_LOW; 370 opt->sl2vl = OSM_DEFAULT_QOS_SL2VL; 371} 372 373static void subn_init_qos_options(IN osm_qos_options_t * opt) 374{ 375 opt->max_vls = 0; 376 opt->high_limit = -1; 377 opt->vlarb_high = NULL; 378 opt->vlarb_low = NULL; 379 opt->sl2vl = NULL; 380} 381 382/********************************************************************** 383 **********************************************************************/ 384void osm_subn_set_default_opt(IN osm_subn_opt_t * const p_opt) 385{ 386 memset(p_opt, 0, sizeof(osm_subn_opt_t)); 387 p_opt->guid = 0; 388 p_opt->m_key = OSM_DEFAULT_M_KEY; 389 p_opt->sm_key = OSM_DEFAULT_SM_KEY; 390 p_opt->sa_key = OSM_DEFAULT_SA_KEY; 391 p_opt->subnet_prefix = IB_DEFAULT_SUBNET_PREFIX; 392 p_opt->m_key_lease_period = 0; 393 p_opt->sweep_interval = OSM_DEFAULT_SWEEP_INTERVAL_SECS; 394 p_opt->max_wire_smps = OSM_DEFAULT_SMP_MAX_ON_WIRE; 395 p_opt->console = OSM_DEFAULT_CONSOLE; 396 p_opt->console_port = OSM_DEFAULT_CONSOLE_PORT; 397 p_opt->transaction_timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; 398 /* by default we will consider waiting for 50x transaction timeout normal */ 399 p_opt->max_msg_fifo_timeout = 50 * OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; 400 p_opt->sm_priority = OSM_DEFAULT_SM_PRIORITY; 401 p_opt->lmc = OSM_DEFAULT_LMC; 402 p_opt->lmc_esp0 = FALSE; 403 p_opt->max_op_vls = OSM_DEFAULT_MAX_OP_VLS; 404 p_opt->force_link_speed = 15; 405 p_opt->reassign_lids = FALSE; 406 p_opt->ignore_other_sm = FALSE; 407 p_opt->single_thread = FALSE; 408 p_opt->disable_multicast = FALSE; 409 p_opt->force_log_flush = FALSE; 410 p_opt->subnet_timeout = OSM_DEFAULT_SUBNET_TIMEOUT; 411 p_opt->packet_life_time = OSM_DEFAULT_SWITCH_PACKET_LIFE; 412 p_opt->vl_stall_count = OSM_DEFAULT_VL_STALL_COUNT; 413 p_opt->leaf_vl_stall_count = OSM_DEFAULT_LEAF_VL_STALL_COUNT; 414 p_opt->head_of_queue_lifetime = OSM_DEFAULT_HEAD_OF_QUEUE_LIFE; 415 p_opt->leaf_head_of_queue_lifetime = 416 OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE; 417 p_opt->local_phy_errors_threshold = OSM_DEFAULT_ERROR_THRESHOLD; 418 p_opt->overrun_errors_threshold = OSM_DEFAULT_ERROR_THRESHOLD; 419 p_opt->sminfo_polling_timeout = 420 OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS; 421 p_opt->polling_retry_number = OSM_SM_DEFAULT_POLLING_RETRY_NUMBER; 422 p_opt->force_heavy_sweep = FALSE; 423 p_opt->log_flags = OSM_LOG_DEFAULT_LEVEL; 424 p_opt->honor_guid2lid_file = FALSE; 425 p_opt->daemon = FALSE; 426 p_opt->sm_inactive = FALSE; 427 p_opt->babbling_port_policy = FALSE; 428#ifdef ENABLE_OSM_PERF_MGR 429 p_opt->perfmgr = FALSE; 430 p_opt->perfmgr_redir = TRUE; 431 p_opt->perfmgr_sweep_time_s = OSM_PERFMGR_DEFAULT_SWEEP_TIME_S; 432 p_opt->perfmgr_max_outstanding_queries = 433 OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES; 434 p_opt->event_db_dump_file = NULL; /* use default */ 435#endif /* ENABLE_OSM_PERF_MGR */ 436 437 p_opt->event_plugin_name = NULL; 438 p_opt->node_name_map_name = NULL; 439 440 p_opt->dump_files_dir = getenv("OSM_TMP_DIR"); 441 if (!p_opt->dump_files_dir || !(*p_opt->dump_files_dir)) 442 p_opt->dump_files_dir = OSM_DEFAULT_TMP_DIR; 443 444 p_opt->log_file = OSM_DEFAULT_LOG_FILE; 445 p_opt->log_max_size = 0; 446 p_opt->partition_config_file = OSM_DEFAULT_PARTITION_CONFIG_FILE; 447 p_opt->no_partition_enforcement = FALSE; 448 p_opt->qos = FALSE; 449 p_opt->qos_policy_file = OSM_DEFAULT_QOS_POLICY_FILE; 450 p_opt->accum_log_file = TRUE; 451 p_opt->port_prof_ignore_file = NULL; 452 p_opt->port_profile_switch_nodes = FALSE; 453 p_opt->sweep_on_trap = TRUE; 454 p_opt->use_ucast_cache = FALSE; 455 p_opt->routing_engine_names = NULL; 456 p_opt->connect_roots = FALSE; 457 p_opt->lid_matrix_dump_file = NULL; 458 p_opt->lfts_file = NULL; 459 p_opt->root_guid_file = NULL; 460 p_opt->cn_guid_file = NULL; 461 p_opt->ids_guid_file = NULL; 462 p_opt->guid_routing_order_file = NULL; 463 p_opt->sa_db_file = NULL; 464 p_opt->exit_on_fatal = TRUE; 465 p_opt->enable_quirks = FALSE; 466 p_opt->no_clients_rereg = FALSE; 467 p_opt->prefix_routes_file = OSM_DEFAULT_PREFIX_ROUTES_FILE; 468 p_opt->consolidate_ipv6_snm_req = FALSE; 469 subn_init_qos_options(&p_opt->qos_options); 470 subn_init_qos_options(&p_opt->qos_ca_options); 471 subn_init_qos_options(&p_opt->qos_sw0_options); 472 subn_init_qos_options(&p_opt->qos_swe_options); 473 subn_init_qos_options(&p_opt->qos_rtr_options); 474} 475 476/********************************************************************** 477 **********************************************************************/ 478static void log_report(const char *fmt, ...) 479{ 480 char buf[128]; 481 va_list args; 482 va_start(args, fmt); 483 vsnprintf(buf, sizeof(buf), fmt, args); 484 va_end(args); 485 printf("%s", buf); 486 cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0); 487} 488 489static void log_config_value(char *name, const char *fmt, ...) 490{ 491 char buf[128]; 492 va_list args; 493 unsigned n; 494 va_start(args, fmt); 495 n = snprintf(buf, sizeof(buf), " Loading Cached Option:%s = ", name); 496 if (n > sizeof(buf)) 497 n = sizeof(buf); 498 n += vsnprintf(buf + n, sizeof(buf) - n, fmt, args); 499 if (n > sizeof(buf)) 500 n = sizeof(buf); 501 snprintf(buf + n, sizeof(buf) - n, "\n"); 502 va_end(args); 503 printf("%s", buf); 504 cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0); 505} 506 507static void 508opts_unpack_net64(IN char *p_req_key, 509 IN char *p_key, IN char *p_val_str, IN uint64_t * p_val) 510{ 511 if (!strcmp(p_req_key, p_key)) { 512 uint64_t val = strtoull(p_val_str, NULL, 0); 513 if (cl_hton64(val) != *p_val) { 514 log_config_value(p_key, "0x%016" PRIx64, val); 515 *p_val = cl_ntoh64(val); 516 } 517 } 518} 519 520/********************************************************************** 521 **********************************************************************/ 522static void 523opts_unpack_uint32(IN char *p_req_key, 524 IN char *p_key, IN char *p_val_str, IN uint32_t * p_val) 525{ 526 if (!strcmp(p_req_key, p_key)) { 527 uint32_t val = strtoul(p_val_str, NULL, 0); 528 if (val != *p_val) { 529 log_config_value(p_key, "%u", val); 530 *p_val = val; 531 } 532 } 533} 534 535/********************************************************************** 536 **********************************************************************/ 537static void 538opts_unpack_int32(IN char *p_req_key, 539 IN char *p_key, IN char *p_val_str, IN int32_t * p_val) 540{ 541 if (!strcmp(p_req_key, p_key)) { 542 int32_t val = strtol(p_val_str, NULL, 0); 543 if (val != *p_val) { 544 log_config_value(p_key, "%d", val); 545 *p_val = val; 546 } 547 } 548} 549 550/********************************************************************** 551 **********************************************************************/ 552static void 553opts_unpack_uint16(IN char *p_req_key, 554 IN char *p_key, IN char *p_val_str, IN uint16_t * p_val) 555{ 556 if (!strcmp(p_req_key, p_key)) { 557 uint16_t val = (uint16_t) strtoul(p_val_str, NULL, 0); 558 if (val != *p_val) { 559 log_config_value(p_key, "%u", val); 560 *p_val = val; 561 } 562 } 563} 564 565/********************************************************************** 566 **********************************************************************/ 567static void 568opts_unpack_net16(IN char *p_req_key, 569 IN char *p_key, IN char *p_val_str, IN uint16_t * p_val) 570{ 571 if (!strcmp(p_req_key, p_key)) { 572 uint32_t val; 573 val = strtoul(p_val_str, NULL, 0); 574 CL_ASSERT(val < 0x10000); 575 if (cl_hton32(val) != *p_val) { 576 log_config_value(p_key, "0x%04x", val); 577 *p_val = cl_hton16((uint16_t) val); 578 } 579 } 580} 581 582/********************************************************************** 583 **********************************************************************/ 584static void 585opts_unpack_uint8(IN char *p_req_key, 586 IN char *p_key, IN char *p_val_str, IN uint8_t * p_val) 587{ 588 if (!strcmp(p_req_key, p_key)) { 589 uint32_t val; 590 val = strtoul(p_val_str, NULL, 0); 591 CL_ASSERT(val < 0x100); 592 if (val != *p_val) { 593 log_config_value(p_key, "%u", val); 594 *p_val = (uint8_t) val; 595 } 596 } 597} 598 599/********************************************************************** 600 **********************************************************************/ 601static void 602opts_unpack_boolean(IN char *p_req_key, 603 IN char *p_key, IN char *p_val_str, IN boolean_t * p_val) 604{ 605 if (!strcmp(p_req_key, p_key) && p_val_str) { 606 boolean_t val; 607 if (strcmp("TRUE", p_val_str)) 608 val = FALSE; 609 else 610 val = TRUE; 611 612 if (val != *p_val) { 613 log_config_value(p_key, "%s", p_val_str); 614 *p_val = val; 615 } 616 } 617} 618 619/********************************************************************** 620 **********************************************************************/ 621static void 622opts_unpack_charp(IN char *p_req_key, 623 IN char *p_key, IN char *p_val_str, IN char **p_val) 624{ 625 if (!strcmp(p_req_key, p_key) && p_val_str) { 626 const char *current_str = *p_val ? *p_val : null_str ; 627 if (strcmp(p_val_str, current_str)) { 628 log_config_value(p_key, "%s", p_val_str); 629 /* special case the "(null)" string */ 630 if (strcmp(null_str, p_val_str) == 0) { 631 *p_val = NULL; 632 } else { 633 /* 634 Ignore the possible memory leak here; 635 the pointer may be to a static default. 636 */ 637 *p_val = strdup(p_val_str); 638 } 639 } 640 } 641} 642 643/********************************************************************** 644 **********************************************************************/ 645static char *clean_val(char *val) 646{ 647 char *p = val; 648 /* clean leading spaces */ 649 while (isspace(*p)) 650 p++; 651 val = p; 652 if (!*val) 653 return val; 654 /* clean trailing spaces */ 655 p = val + strlen(val) - 1; 656 while (p > val && isspace(*p)) 657 p--; 658 p[1] = '\0'; 659 /* clean quotas */ 660 if ((*val == '\"' && *p == '\"') || (*val == '\'' && *p == '\'')) { 661 val++; 662 p--; 663 } 664 return val; 665} 666 667/********************************************************************** 668 **********************************************************************/ 669static void 670subn_parse_qos_options(IN const char *prefix, 671 IN char *p_key, 672 IN char *p_val_str, IN osm_qos_options_t * opt) 673{ 674 char name[256]; 675 676 snprintf(name, sizeof(name), "%s_max_vls", prefix); 677 opts_unpack_uint32(name, p_key, p_val_str, &opt->max_vls); 678 snprintf(name, sizeof(name), "%s_high_limit", prefix); 679 opts_unpack_int32(name, p_key, p_val_str, &opt->high_limit); 680 snprintf(name, sizeof(name), "%s_vlarb_high", prefix); 681 opts_unpack_charp(name, p_key, p_val_str, &opt->vlarb_high); 682 snprintf(name, sizeof(name), "%s_vlarb_low", prefix); 683 opts_unpack_charp(name, p_key, p_val_str, &opt->vlarb_low); 684 snprintf(name, sizeof(name), "%s_sl2vl", prefix); 685 opts_unpack_charp(name, p_key, p_val_str, &opt->sl2vl); 686} 687 688static int 689subn_dump_qos_options(FILE * file, 690 const char *set_name, 691 const char *prefix, osm_qos_options_t * opt) 692{ 693 return fprintf(file, "# %s\n" 694 "%s_max_vls %u\n" 695 "%s_high_limit %d\n" 696 "%s_vlarb_high %s\n" 697 "%s_vlarb_low %s\n" 698 "%s_sl2vl %s\n", 699 set_name, 700 prefix, opt->max_vls, 701 prefix, opt->high_limit, 702 prefix, opt->vlarb_high, 703 prefix, opt->vlarb_low, prefix, opt->sl2vl); 704} 705 706/********************************************************************** 707 **********************************************************************/ 708static ib_api_status_t 709append_prefix_route(IN osm_subn_t * const p_subn, uint64_t prefix, uint64_t guid) 710{ 711 osm_prefix_route_t *route; 712 713 route = malloc(sizeof *route); 714 if (! route) { 715 OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "out of memory"); 716 return IB_ERROR; 717 } 718 719 route->prefix = cl_hton64(prefix); 720 route->guid = cl_hton64(guid); 721 cl_qlist_insert_tail(&p_subn->prefix_routes_list, &route->list_item); 722 return IB_SUCCESS; 723} 724 725static ib_api_status_t 726osm_parse_prefix_routes_file(IN osm_subn_t * const p_subn) 727{ 728 osm_log_t *log = &p_subn->p_osm->log; 729 FILE *fp; 730 char buf[1024]; 731 int line = 0; 732 int errors = 0; 733 734 while (!cl_is_qlist_empty(&p_subn->prefix_routes_list)) { 735 cl_list_item_t *item = cl_qlist_remove_head(&p_subn->prefix_routes_list); 736 free(item); 737 } 738 739 fp = fopen(p_subn->opt.prefix_routes_file, "r"); 740 if (! fp) { 741 if (errno == ENOENT) 742 return IB_SUCCESS; 743 744 OSM_LOG(log, OSM_LOG_ERROR, "fopen(%s) failed: %s", 745 p_subn->opt.prefix_routes_file, strerror(errno)); 746 return IB_ERROR; 747 } 748 749 while (fgets(buf, sizeof buf, fp) != NULL) { 750 char *p_prefix, *p_guid, *p_extra, *p_last, *p_end; 751 uint64_t prefix, guid; 752 753 line++; 754 if (errors > 10) 755 break; 756 757 p_prefix = strtok_r(buf, " \t\n", &p_last); 758 if (! p_prefix) 759 continue; /* ignore blank lines */ 760 761 if (*p_prefix == '#') 762 continue; /* ignore comment lines */ 763 764 p_guid = strtok_r(NULL, " \t\n", &p_last); 765 if (! p_guid) { 766 OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: missing GUID\n", 767 p_subn->opt.prefix_routes_file, line); 768 errors++; 769 continue; 770 } 771 772 p_extra = strtok_r(NULL, " \t\n", &p_last); 773 if (p_extra && *p_extra != '#') { 774 OSM_LOG(log, OSM_LOG_INFO, "%s:%d: extra tokens ignored\n", 775 p_subn->opt.prefix_routes_file, line); 776 } 777 778 if (strcmp(p_prefix, "*") == 0) 779 prefix = 0; 780 else { 781 prefix = strtoull(p_prefix, &p_end, 16); 782 if (*p_end != '\0') { 783 OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: illegal prefix: %s\n", 784 p_subn->opt.prefix_routes_file, line, p_prefix); 785 errors++; 786 continue; 787 } 788 } 789 790 if (strcmp(p_guid, "*") == 0) 791 guid = 0; 792 else { 793 guid = strtoull(p_guid, &p_end, 16); 794 if (*p_end != '\0' && *p_end != '#') { 795 OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: illegal GUID: %s\n", 796 p_subn->opt.prefix_routes_file, line, p_guid); 797 errors++; 798 continue; 799 } 800 } 801 802 if (append_prefix_route(p_subn, prefix, guid) != IB_SUCCESS) { 803 errors++; 804 break; 805 } 806 } 807 808 fclose(fp); 809 return (errors == 0) ? IB_SUCCESS : IB_ERROR; 810} 811 812/********************************************************************** 813 **********************************************************************/ 814static void subn_verify_max_vls(unsigned *max_vls, const char *prefix, unsigned dflt) 815{ 816 if (!(*max_vls) || *max_vls > 15) { 817 log_report(" Invalid Cached Option: %s_max_vls=%u: " 818 "Using Default = %u\n", prefix, *max_vls, dflt); 819 *max_vls = dflt; 820 } 821} 822 823static void subn_verify_high_limit(int *high_limit, const char *prefix, int dflt) 824{ 825 if (*high_limit < 0 || *high_limit > 255) { 826 log_report(" Invalid Cached Option: %s_high_limit=%d: " 827 "Using Default: %d\n", prefix, *high_limit, dflt); 828 *high_limit = dflt; 829 } 830} 831 832static void subn_verify_vlarb(char **vlarb, const char *prefix, 833 const char *suffix, char *dflt) 834{ 835 char *str, *tok, *end, *ptr; 836 int count = 0; 837 838 if (*vlarb == NULL) { 839 log_report(" Invalid Cached Option: %s_vlarb_%s: " 840 "Using Default\n", prefix, suffix); 841 *vlarb = dflt; 842 return; 843 } 844 845 str = strdup(*vlarb); 846 847 tok = strtok_r(str, ",\n", &ptr); 848 while (tok) { 849 char *vl_str, *weight_str; 850 851 vl_str = tok; 852 weight_str = strchr(tok, ':'); 853 854 if (weight_str) { 855 long vl, weight; 856 857 *weight_str = '\0'; 858 weight_str++; 859 860 vl = strtol(vl_str, &end, 0); 861 862 if (*end) 863 log_report(" Warning: Cached Option " 864 "%s_vlarb_%s:vl=%s" 865 " improperly formatted\n", 866 prefix, suffix, vl_str); 867 else if (vl < 0 || vl > 14) 868 log_report(" Warning: Cached Option " 869 "%s_vlarb_%s:vl=%ld out of range\n", 870 prefix, suffix, vl); 871 872 weight = strtol(weight_str, &end, 0); 873 874 if (*end) 875 log_report(" Warning: Cached Option " 876 "%s_vlarb_%s:weight=%s " 877 "improperly formatted\n", 878 prefix, suffix, weight_str); 879 else if (weight < 0 || weight > 255) 880 log_report(" Warning: Cached Option " 881 "%s_vlarb_%s:weight=%ld " 882 "out of range\n", 883 prefix, suffix, weight); 884 } else 885 log_report(" Warning: Cached Option " 886 "%s_vlarb_%s:vl:weight=%s " 887 "improperly formatted\n", 888 prefix, suffix, tok); 889 890 count++; 891 tok = strtok_r(NULL, ",\n", &ptr); 892 } 893 894 if (count > 64) 895 log_report(" Warning: Cached Option %s_vlarb_%s: > 64 listed:" 896 " excess vl:weight pairs will be dropped\n", 897 prefix, suffix); 898 899 free(str); 900} 901 902static void subn_verify_sl2vl(char **sl2vl, const char *prefix, char *dflt) 903{ 904 char *str, *tok, *end, *ptr; 905 int count = 0; 906 907 if (*sl2vl == NULL) { 908 log_report(" Invalid Cached Option: %s_sl2vl: Using Default\n", 909 prefix); 910 *sl2vl = dflt; 911 return; 912 } 913 914 str = strdup(*sl2vl); 915 916 tok = strtok_r(str, ",\n", &ptr); 917 while (tok) { 918 long vl = strtol(tok, &end, 0); 919 920 if (*end) 921 log_report(" Warning: Cached Option %s_sl2vl:vl=%s " 922 "improperly formatted\n", prefix, tok); 923 else if (vl < 0 || vl > 15) 924 log_report(" Warning: Cached Option %s_sl2vl:vl=%ld " 925 "out of range\n", prefix, vl); 926 927 count++; 928 tok = strtok_r(NULL, ",\n", &ptr); 929 } 930 931 if (count < 16) 932 log_report(" Warning: Cached Option %s_sl2vl: < 16 VLs " 933 "listed\n", prefix); 934 935 if (count > 16) 936 log_report(" Warning: Cached Option %s_sl2vl: > 16 listed: " 937 "excess VLs will be dropped\n", prefix); 938 939 free(str); 940} 941 942static void subn_verify_qos_set(osm_qos_options_t *set, const char *prefix, 943 osm_qos_options_t *dflt) 944{ 945 subn_verify_max_vls(&set->max_vls, prefix, dflt->max_vls); 946 subn_verify_high_limit(&set->high_limit, prefix, dflt->high_limit); 947 subn_verify_vlarb(&set->vlarb_low, prefix, "low", dflt->vlarb_low); 948 subn_verify_vlarb(&set->vlarb_high, prefix, "high", dflt->vlarb_high); 949 subn_verify_sl2vl(&set->sl2vl, prefix, dflt->sl2vl); 950} 951 952int osm_subn_verify_config(IN osm_subn_opt_t * const p_opts) 953{ 954 if (p_opts->lmc > 7) { 955 log_report(" Invalid Cached Option Value:lmc = %u:" 956 "Using Default:%u\n", p_opts->lmc, OSM_DEFAULT_LMC); 957 p_opts->lmc = OSM_DEFAULT_LMC; 958 } 959 960 if (15 < p_opts->sm_priority) { 961 log_report(" Invalid Cached Option Value:sm_priority = %u:" 962 "Using Default:%u\n", 963 p_opts->sm_priority, OSM_DEFAULT_SM_PRIORITY); 964 p_opts->sm_priority = OSM_DEFAULT_SM_PRIORITY; 965 } 966 967 if ((15 < p_opts->force_link_speed) || 968 (p_opts->force_link_speed > 7 && p_opts->force_link_speed < 15)) { 969 log_report(" Invalid Cached Option Value:force_link_speed = %u:" 970 "Using Default:%u\n", p_opts->force_link_speed, 971 IB_PORT_LINK_SPEED_ENABLED_MASK); 972 p_opts->force_link_speed = IB_PORT_LINK_SPEED_ENABLED_MASK; 973 } 974 975 if (strcmp(p_opts->console, OSM_DISABLE_CONSOLE) 976 && strcmp(p_opts->console, OSM_LOCAL_CONSOLE) 977#ifdef ENABLE_OSM_CONSOLE_SOCKET 978 && strcmp(p_opts->console, OSM_LOOPBACK_CONSOLE) 979 && strcmp(p_opts->console, OSM_REMOTE_CONSOLE) 980#endif 981 ) { 982 log_report(" Invalid Cached Option Value:console = %s" 983 ", Using Default:%s\n", 984 p_opts->console, OSM_DEFAULT_CONSOLE); 985 p_opts->console = OSM_DEFAULT_CONSOLE; 986 } 987 988 if (p_opts->qos) { 989 osm_qos_options_t dflt; 990 991 /* the default options in qos_options must be correct. 992 * every other one need not be, b/c those will default 993 * back to whatever is in qos_options. 994 */ 995 996 subn_set_default_qos_options(&dflt); 997 998 subn_verify_qos_set(&p_opts->qos_options, "qos", &dflt); 999 subn_verify_qos_set(&p_opts->qos_ca_options, "qos_ca", 1000 &p_opts->qos_options); 1001 subn_verify_qos_set(&p_opts->qos_sw0_options, "qos_sw0", 1002 &p_opts->qos_options); 1003 subn_verify_qos_set(&p_opts->qos_swe_options, "qos_swe", 1004 &p_opts->qos_options); 1005 subn_verify_qos_set(&p_opts->qos_rtr_options, "qos_rtr", 1006 &p_opts->qos_options); 1007 } 1008 1009#ifdef ENABLE_OSM_PERF_MGR 1010 if (p_opts->perfmgr_sweep_time_s < 1) { 1011 log_report(" Invalid Cached Option Value:perfmgr_sweep_time_s " 1012 "= %u Using Default:%u\n", 1013 p_opts->perfmgr_sweep_time_s, 1014 OSM_PERFMGR_DEFAULT_SWEEP_TIME_S); 1015 p_opts->perfmgr_sweep_time_s = OSM_PERFMGR_DEFAULT_SWEEP_TIME_S; 1016 } 1017 if (p_opts->perfmgr_max_outstanding_queries < 1) { 1018 log_report(" Invalid Cached Option Value:" 1019 "perfmgr_max_outstanding_queries = %u" 1020 " Using Default:%u\n", 1021 p_opts->perfmgr_max_outstanding_queries, 1022 OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES); 1023 p_opts->perfmgr_max_outstanding_queries = 1024 OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES; 1025 } 1026#endif 1027 1028 return 0; 1029} 1030 1031/********************************************************************** 1032 **********************************************************************/ 1033int osm_subn_parse_conf_file(char *file_name, osm_subn_opt_t * const p_opts) 1034{ 1035 char line[1024]; 1036 FILE *opts_file; 1037 char *p_key, *p_val; 1038 1039 opts_file = fopen(file_name, "r"); 1040 if (!opts_file) { 1041 if (errno == ENOENT) 1042 return 1; 1043 printf("cannot open file \'%s\': %s\n", 1044 file_name, strerror(errno)); 1045 return -1; 1046 } 1047 1048 printf(" Reading Cached Option File: %s\n", file_name); 1049 cl_log_event("OpenSM", CL_LOG_INFO, line, NULL, 0); 1050 1051 p_opts->config_file = file_name; 1052 1053 while (fgets(line, 1023, opts_file) != NULL) { 1054 /* get the first token */ 1055 p_key = strtok_r(line, " \t\n", &p_val); 1056 if (!p_key) 1057 continue; 1058 1059 p_val = clean_val(p_val); 1060 1061 opts_unpack_net64("guid", p_key, p_val, &p_opts->guid); 1062 1063 opts_unpack_net64("m_key", p_key, p_val, &p_opts->m_key); 1064 1065 opts_unpack_net64("sm_key", p_key, p_val, &p_opts->sm_key); 1066 1067 opts_unpack_net64("sa_key", p_key, p_val, &p_opts->sa_key); 1068 1069 opts_unpack_net64("subnet_prefix", 1070 p_key, p_val, &p_opts->subnet_prefix); 1071 1072 opts_unpack_net16("m_key_lease_period", 1073 p_key, p_val, &p_opts->m_key_lease_period); 1074 1075 opts_unpack_uint32("sweep_interval", 1076 p_key, p_val, &p_opts->sweep_interval); 1077 1078 opts_unpack_uint32("max_wire_smps", 1079 p_key, p_val, &p_opts->max_wire_smps); 1080 1081 opts_unpack_charp("console", p_key, p_val, &p_opts->console); 1082 1083 opts_unpack_uint16("console_port", 1084 p_key, p_val, &p_opts->console_port); 1085 1086 opts_unpack_uint32("transaction_timeout", 1087 p_key, p_val, &p_opts->transaction_timeout); 1088 1089 opts_unpack_uint32("max_msg_fifo_timeout", 1090 p_key, p_val, &p_opts->max_msg_fifo_timeout); 1091 1092 opts_unpack_uint8("sm_priority", 1093 p_key, p_val, &p_opts->sm_priority); 1094 1095 opts_unpack_uint8("lmc", p_key, p_val, &p_opts->lmc); 1096 1097 opts_unpack_boolean("lmc_esp0", 1098 p_key, p_val, &p_opts->lmc_esp0); 1099 1100 opts_unpack_uint8("max_op_vls", 1101 p_key, p_val, &p_opts->max_op_vls); 1102 1103 opts_unpack_uint8("force_link_speed", 1104 p_key, p_val, &p_opts->force_link_speed); 1105 1106 opts_unpack_boolean("reassign_lids", 1107 p_key, p_val, &p_opts->reassign_lids); 1108 1109 opts_unpack_boolean("ignore_other_sm", 1110 p_key, p_val, &p_opts->ignore_other_sm); 1111 1112 opts_unpack_boolean("single_thread", 1113 p_key, p_val, &p_opts->single_thread); 1114 1115 opts_unpack_boolean("disable_multicast", 1116 p_key, p_val, &p_opts->disable_multicast); 1117 1118 opts_unpack_boolean("force_log_flush", 1119 p_key, p_val, &p_opts->force_log_flush); 1120 1121 opts_unpack_uint8("subnet_timeout", 1122 p_key, p_val, &p_opts->subnet_timeout); 1123 1124 opts_unpack_uint8("packet_life_time", 1125 p_key, p_val, &p_opts->packet_life_time); 1126 1127 opts_unpack_uint8("vl_stall_count", 1128 p_key, p_val, &p_opts->vl_stall_count); 1129 1130 opts_unpack_uint8("leaf_vl_stall_count", 1131 p_key, p_val, &p_opts->leaf_vl_stall_count); 1132 1133 opts_unpack_uint8("head_of_queue_lifetime", 1134 p_key, p_val, 1135 &p_opts->head_of_queue_lifetime); 1136 1137 opts_unpack_uint8("leaf_head_of_queue_lifetime", p_key, p_val, 1138 &p_opts->leaf_head_of_queue_lifetime); 1139 1140 opts_unpack_uint8("local_phy_errors_threshold", p_key, p_val, 1141 &p_opts->local_phy_errors_threshold); 1142 1143 opts_unpack_uint8("overrun_errors_threshold", 1144 p_key, p_val, 1145 &p_opts->overrun_errors_threshold); 1146 1147 opts_unpack_uint32("sminfo_polling_timeout", 1148 p_key, p_val, 1149 &p_opts->sminfo_polling_timeout); 1150 1151 opts_unpack_uint32("polling_retry_number", 1152 p_key, p_val, &p_opts->polling_retry_number); 1153 1154 opts_unpack_boolean("force_heavy_sweep", 1155 p_key, p_val, &p_opts->force_heavy_sweep); 1156 1157 opts_unpack_uint8("log_flags", 1158 p_key, p_val, &p_opts->log_flags); 1159 1160 opts_unpack_charp("port_prof_ignore_file", p_key, p_val, 1161 &p_opts->port_prof_ignore_file); 1162 1163 opts_unpack_boolean("port_profile_switch_nodes", p_key, p_val, 1164 &p_opts->port_profile_switch_nodes); 1165 1166 opts_unpack_boolean("sweep_on_trap", 1167 p_key, p_val, &p_opts->sweep_on_trap); 1168 1169 opts_unpack_charp("routing_engine", 1170 p_key, p_val, &p_opts->routing_engine_names); 1171 1172 opts_unpack_boolean("connect_roots", 1173 p_key, p_val, &p_opts->connect_roots); 1174 1175 opts_unpack_boolean("use_ucast_cache", 1176 p_key, p_val, &p_opts->use_ucast_cache); 1177 1178 opts_unpack_charp("log_file", p_key, p_val, &p_opts->log_file); 1179 1180 opts_unpack_uint32("log_max_size", 1181 p_key, p_val, 1182 (void *) & p_opts->log_max_size); 1183 p_opts->log_max_size *= 1024 * 1024; /* convert to MB */ 1184 1185 opts_unpack_charp("partition_config_file", 1186 p_key, p_val, &p_opts->partition_config_file); 1187 1188 opts_unpack_boolean("no_partition_enforcement", p_key, p_val, 1189 &p_opts->no_partition_enforcement); 1190 1191 opts_unpack_boolean("qos", p_key, p_val, &p_opts->qos); 1192 1193 opts_unpack_charp("qos_policy_file", 1194 p_key, p_val, &p_opts->qos_policy_file); 1195 1196 opts_unpack_boolean("accum_log_file", 1197 p_key, p_val, &p_opts->accum_log_file); 1198 1199 opts_unpack_charp("dump_files_dir", 1200 p_key, p_val, &p_opts->dump_files_dir); 1201 1202 opts_unpack_charp("lid_matrix_dump_file", 1203 p_key, p_val, &p_opts->lid_matrix_dump_file); 1204 1205 opts_unpack_charp("lfts_file", 1206 p_key, p_val, &p_opts->lfts_file); 1207 1208 opts_unpack_charp("root_guid_file", 1209 p_key, p_val, &p_opts->root_guid_file); 1210 1211 opts_unpack_charp("cn_guid_file", 1212 p_key, p_val, &p_opts->cn_guid_file); 1213 1214 opts_unpack_charp("ids_guid_file", 1215 p_key, p_val, &p_opts->ids_guid_file); 1216 1217 opts_unpack_charp("guid_routing_order_file", 1218 p_key, p_val, &p_opts->guid_routing_order_file); 1219 1220 opts_unpack_charp("sa_db_file", 1221 p_key, p_val, &p_opts->sa_db_file); 1222 1223 opts_unpack_boolean("exit_on_fatal", 1224 p_key, p_val, &p_opts->exit_on_fatal); 1225 1226 opts_unpack_boolean("honor_guid2lid_file", 1227 p_key, p_val, &p_opts->honor_guid2lid_file); 1228 1229 opts_unpack_boolean("daemon", p_key, p_val, &p_opts->daemon); 1230 1231 opts_unpack_boolean("sm_inactive", 1232 p_key, p_val, &p_opts->sm_inactive); 1233 1234 opts_unpack_boolean("babbling_port_policy", 1235 p_key, p_val, 1236 &p_opts->babbling_port_policy); 1237 1238#ifdef ENABLE_OSM_PERF_MGR 1239 opts_unpack_boolean("perfmgr", p_key, p_val, &p_opts->perfmgr); 1240 1241 opts_unpack_boolean("perfmgr_redir", 1242 p_key, p_val, &p_opts->perfmgr_redir); 1243 1244 opts_unpack_uint16("perfmgr_sweep_time_s", 1245 p_key, p_val, &p_opts->perfmgr_sweep_time_s); 1246 1247 opts_unpack_uint32("perfmgr_max_outstanding_queries", 1248 p_key, p_val, 1249 &p_opts->perfmgr_max_outstanding_queries); 1250 1251 opts_unpack_charp("event_db_dump_file", 1252 p_key, p_val, &p_opts->event_db_dump_file); 1253#endif /* ENABLE_OSM_PERF_MGR */ 1254 1255 opts_unpack_charp("event_plugin_name", 1256 p_key, p_val, &p_opts->event_plugin_name); 1257 1258 opts_unpack_charp("node_name_map_name", 1259 p_key, p_val, &p_opts->node_name_map_name); 1260 1261 subn_parse_qos_options("qos", 1262 p_key, p_val, &p_opts->qos_options); 1263 1264 subn_parse_qos_options("qos_ca", 1265 p_key, p_val, &p_opts->qos_ca_options); 1266 1267 subn_parse_qos_options("qos_sw0", 1268 p_key, p_val, &p_opts->qos_sw0_options); 1269 1270 subn_parse_qos_options("qos_swe", 1271 p_key, p_val, &p_opts->qos_swe_options); 1272 1273 subn_parse_qos_options("qos_rtr", 1274 p_key, p_val, &p_opts->qos_rtr_options); 1275 1276 opts_unpack_boolean("enable_quirks", 1277 p_key, p_val, &p_opts->enable_quirks); 1278 1279 opts_unpack_boolean("no_clients_rereg", 1280 p_key, p_val, &p_opts->no_clients_rereg); 1281 1282 opts_unpack_charp("prefix_routes_file", 1283 p_key, p_val, &p_opts->prefix_routes_file); 1284 1285 opts_unpack_boolean("consolidate_ipv6_snm_req", 1286 p_key, p_val, &p_opts->consolidate_ipv6_snm_req); 1287 } 1288 fclose(opts_file); 1289 1290 osm_subn_verify_config(p_opts); 1291 1292 return 0; 1293} 1294 1295int osm_subn_rescan_conf_files(IN osm_subn_t * const p_subn) 1296{ 1297 FILE *opts_file; 1298 char line[1024]; 1299 char *p_key, *p_val, *p_last; 1300 1301 if (!p_subn->opt.config_file) 1302 return 0; 1303 1304 opts_file = fopen(p_subn->opt.config_file, "r"); 1305 if (!opts_file) { 1306 if (errno == ENOENT) 1307 return 1; 1308 OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, 1309 "cannot open file \'%s\': %s\n", 1310 p_subn->opt.config_file, strerror(errno)); 1311 return -1; 1312 } 1313 1314 subn_init_qos_options(&p_subn->opt.qos_options); 1315 subn_init_qos_options(&p_subn->opt.qos_ca_options); 1316 subn_init_qos_options(&p_subn->opt.qos_sw0_options); 1317 subn_init_qos_options(&p_subn->opt.qos_swe_options); 1318 subn_init_qos_options(&p_subn->opt.qos_rtr_options); 1319 1320 while (fgets(line, 1023, opts_file) != NULL) { 1321 /* get the first token */ 1322 p_key = strtok_r(line, " \t\n", &p_last); 1323 if (p_key) { 1324 p_val = strtok_r(NULL, " \t\n", &p_last); 1325 1326 subn_parse_qos_options("qos", p_key, p_val, 1327 &p_subn->opt.qos_options); 1328 1329 subn_parse_qos_options("qos_ca", p_key, p_val, 1330 &p_subn->opt.qos_ca_options); 1331 1332 subn_parse_qos_options("qos_sw0", p_key, p_val, 1333 &p_subn->opt.qos_sw0_options); 1334 1335 subn_parse_qos_options("qos_swe", p_key, p_val, 1336 &p_subn->opt.qos_swe_options); 1337 1338 subn_parse_qos_options("qos_rtr", p_key, p_val, 1339 &p_subn->opt.qos_rtr_options); 1340 1341 } 1342 } 1343 fclose(opts_file); 1344 1345 osm_subn_verify_config(&p_subn->opt); 1346 1347 osm_parse_prefix_routes_file(p_subn); 1348 1349 return 0; 1350} 1351 1352/********************************************************************** 1353 **********************************************************************/ 1354int osm_subn_output_conf(FILE *out, IN osm_subn_opt_t *const p_opts) 1355{ 1356 fprintf(out, 1357 "#\n# DEVICE ATTRIBUTES OPTIONS\n#\n" 1358 "# The port GUID on which the OpenSM is running\n" 1359 "guid 0x%016" PRIx64 "\n\n" 1360 "# M_Key value sent to all ports qualifying all Set(PortInfo)\n" 1361 "m_key 0x%016" PRIx64 "\n\n" 1362 "# The lease period used for the M_Key on this subnet in [sec]\n" 1363 "m_key_lease_period %u\n\n" 1364 "# SM_Key value of the SM used for SM authentication\n" 1365 "sm_key 0x%016" PRIx64 "\n\n" 1366 "# SM_Key value to qualify rcv SA queries as 'trusted'\n" 1367 "sa_key 0x%016" PRIx64 "\n\n" 1368 "# Note that for both values above (sm_key and sa_key)\n" 1369 "# OpenSM version 3.2.1 and below used the default value '1'\n" 1370 "# in a host byte order, it is fixed now but you may need to\n" 1371 "# change the values to interoperate with old OpenSM running\n" 1372 "# on a little endian machine.\n\n" 1373 "# Subnet prefix used on this subnet\n" 1374 "subnet_prefix 0x%016" PRIx64 "\n\n" 1375 "# The LMC value used on this subnet\n" 1376 "lmc %u\n\n" 1377 "# lmc_esp0 determines whether LMC value used on subnet is used for\n" 1378 "# enhanced switch port 0. If TRUE, LMC value for subnet is used for\n" 1379 "# ESP0. Otherwise, LMC value for ESP0s is 0.\n" 1380 "lmc_esp0 %s\n\n" 1381 "# The code of maximal time a packet can live in a switch\n" 1382 "# The actual time is 4.096usec * 2^<packet_life_time>\n" 1383 "# The value 0x14 disables this mechanism\n" 1384 "packet_life_time 0x%02x\n\n" 1385 "# The number of sequential packets dropped that cause the port\n" 1386 "# to enter the VLStalled state. The result of setting this value to\n" 1387 "# zero is undefined.\n" 1388 "vl_stall_count 0x%02x\n\n" 1389 "# The number of sequential packets dropped that cause the port\n" 1390 "# to enter the VLStalled state. This value is for switch ports\n" 1391 "# driving a CA or router port. The result of setting this value\n" 1392 "# to zero is undefined.\n" 1393 "leaf_vl_stall_count 0x%02x\n\n" 1394 "# The code of maximal time a packet can wait at the head of\n" 1395 "# transmission queue.\n" 1396 "# The actual time is 4.096usec * 2^<head_of_queue_lifetime>\n" 1397 "# The value 0x14 disables this mechanism\n" 1398 "head_of_queue_lifetime 0x%02x\n\n" 1399 "# The maximal time a packet can wait at the head of queue on\n" 1400 "# switch port connected to a CA or router port\n" 1401 "leaf_head_of_queue_lifetime 0x%02x\n\n" 1402 "# Limit the maximal operational VLs\n" 1403 "max_op_vls %u\n\n" 1404 "# Force PortInfo:LinkSpeedEnabled on switch ports\n" 1405 "# If 0, don't modify PortInfo:LinkSpeedEnabled on switch port\n" 1406 "# Otherwise, use value for PortInfo:LinkSpeedEnabled on switch port\n" 1407 "# Values are (IB Spec 1.2.1, 14.2.5.6 Table 146 \"PortInfo\")\n" 1408 "# 1: 2.5 Gbps\n" 1409 "# 3: 2.5 or 5.0 Gbps\n" 1410 "# 5: 2.5 or 10.0 Gbps\n" 1411 "# 7: 2.5 or 5.0 or 10.0 Gbps\n" 1412 "# 2,4,6,8-14 Reserved\n" 1413 "# Default 15: set to PortInfo:LinkSpeedSupported\n" 1414 "force_link_speed %u\n\n" 1415 "# The subnet_timeout code that will be set for all the ports\n" 1416 "# The actual timeout is 4.096usec * 2^<subnet_timeout>\n" 1417 "subnet_timeout %u\n\n" 1418 "# Threshold of local phy errors for sending Trap 129\n" 1419 "local_phy_errors_threshold 0x%02x\n\n" 1420 "# Threshold of credit overrun errors for sending Trap 130\n" 1421 "overrun_errors_threshold 0x%02x\n\n", 1422 cl_ntoh64(p_opts->guid), 1423 cl_ntoh64(p_opts->m_key), 1424 cl_ntoh16(p_opts->m_key_lease_period), 1425 cl_ntoh64(p_opts->sm_key), 1426 cl_ntoh64(p_opts->sa_key), 1427 cl_ntoh64(p_opts->subnet_prefix), 1428 p_opts->lmc, 1429 p_opts->lmc_esp0 ? "TRUE" : "FALSE", 1430 p_opts->packet_life_time, 1431 p_opts->vl_stall_count, 1432 p_opts->leaf_vl_stall_count, 1433 p_opts->head_of_queue_lifetime, 1434 p_opts->leaf_head_of_queue_lifetime, 1435 p_opts->max_op_vls, 1436 p_opts->force_link_speed, 1437 p_opts->subnet_timeout, 1438 p_opts->local_phy_errors_threshold, 1439 p_opts->overrun_errors_threshold); 1440 1441 fprintf(out, 1442 "#\n# PARTITIONING OPTIONS\n#\n" 1443 "# Partition configuration file to be used\n" 1444 "partition_config_file %s\n\n" 1445 "# Disable partition enforcement by switches\n" 1446 "no_partition_enforcement %s\n\n", 1447 p_opts->partition_config_file, 1448 p_opts->no_partition_enforcement ? "TRUE" : "FALSE"); 1449 1450 fprintf(out, 1451 "#\n# SWEEP OPTIONS\n#\n" 1452 "# The number of seconds between subnet sweeps (0 disables it)\n" 1453 "sweep_interval %u\n\n" 1454 "# If TRUE cause all lids to be reassigned\n" 1455 "reassign_lids %s\n\n" 1456 "# If TRUE forces every sweep to be a heavy sweep\n" 1457 "force_heavy_sweep %s\n\n" 1458 "# If TRUE every trap will cause a heavy sweep.\n" 1459 "# NOTE: successive identical traps (>10) are suppressed\n" 1460 "sweep_on_trap %s\n\n", 1461 p_opts->sweep_interval, 1462 p_opts->reassign_lids ? "TRUE" : "FALSE", 1463 p_opts->force_heavy_sweep ? "TRUE" : "FALSE", 1464 p_opts->sweep_on_trap ? "TRUE" : "FALSE"); 1465 1466 fprintf(out, 1467 "#\n# ROUTING OPTIONS\n#\n" 1468 "# If TRUE count switches as link subscriptions\n" 1469 "port_profile_switch_nodes %s\n\n", 1470 p_opts->port_profile_switch_nodes ? "TRUE" : "FALSE"); 1471 1472 fprintf(out, 1473 "# Name of file with port guids to be ignored by port profiling\n" 1474 "port_prof_ignore_file %s\n\n", p_opts->port_prof_ignore_file ? 1475 p_opts->port_prof_ignore_file : null_str); 1476 1477 fprintf(out, 1478 "# Routing engine\n" 1479 "# Multiple routing engines can be specified separated by\n" 1480 "# commas so that specific ordering of routing algorithms will\n" 1481 "# be tried if earlier routing engines fail.\n" 1482 "# Supported engines: minhop, updn, file, ftree, lash, dor\n" 1483 "routing_engine %s\n\n", p_opts->routing_engine_names ? 1484 p_opts->routing_engine_names : null_str); 1485 1486 fprintf(out, 1487 "# Connect roots (use FALSE if unsure)\n" 1488 "connect_roots %s\n\n", 1489 p_opts->connect_roots ? "TRUE" : "FALSE"); 1490 1491 fprintf(out, 1492 "# Use unicast routing cache (use FALSE if unsure)\n" 1493 "use_ucast_cache %s\n\n", 1494 p_opts->use_ucast_cache ? "TRUE" : "FALSE"); 1495 1496 fprintf(out, 1497 "# Lid matrix dump file name\n" 1498 "lid_matrix_dump_file %s\n\n", p_opts->lid_matrix_dump_file ? 1499 p_opts->lid_matrix_dump_file : null_str); 1500 1501 fprintf(out, 1502 "# LFTs file name\nlfts_file %s\n\n", 1503 p_opts->lfts_file ? p_opts->lfts_file : null_str); 1504 1505 fprintf(out, 1506 "# The file holding the root node guids (for fat-tree or Up/Down)\n" 1507 "# One guid in each line\nroot_guid_file %s\n\n", 1508 p_opts->root_guid_file ? p_opts->root_guid_file : null_str); 1509 1510 fprintf(out, 1511 "# The file holding the fat-tree compute node guids\n" 1512 "# One guid in each line\ncn_guid_file %s\n\n", 1513 p_opts->cn_guid_file ? p_opts->cn_guid_file : null_str); 1514 1515 fprintf(out, 1516 "# The file holding the node ids which will be used by" 1517 " Up/Down algorithm instead\n# of GUIDs (one guid and" 1518 " id in each line)\nids_guid_file %s\n\n", 1519 p_opts->ids_guid_file ? p_opts->ids_guid_file : null_str); 1520 1521 fprintf(out, 1522 "# The file holding guid routing order guids (for MinHop and Up/Down)\n" 1523 "guid_routing_order_file %s\n\n", 1524 p_opts->guid_routing_order_file ? p_opts->guid_routing_order_file : null_str); 1525 1526 fprintf(out, 1527 "# SA database file name\nsa_db_file %s\n\n", 1528 p_opts->sa_db_file ? p_opts->sa_db_file : null_str); 1529 1530 fprintf(out, 1531 "#\n# HANDOVER - MULTIPLE SMs OPTIONS\n#\n" 1532 "# SM priority used for deciding who is the master\n" 1533 "# Range goes from 0 (lowest priority) to 15 (highest).\n" 1534 "sm_priority %u\n\n" 1535 "# If TRUE other SMs on the subnet should be ignored\n" 1536 "ignore_other_sm %s\n\n" 1537 "# Timeout in [msec] between two polls of active master SM\n" 1538 "sminfo_polling_timeout %u\n\n" 1539 "# Number of failing polls of remote SM that declares it dead\n" 1540 "polling_retry_number %u\n\n" 1541 "# If TRUE honor the guid2lid file when coming out of standby\n" 1542 "# state, if such file exists and is valid\n" 1543 "honor_guid2lid_file %s\n\n", 1544 p_opts->sm_priority, 1545 p_opts->ignore_other_sm ? "TRUE" : "FALSE", 1546 p_opts->sminfo_polling_timeout, 1547 p_opts->polling_retry_number, 1548 p_opts->honor_guid2lid_file ? "TRUE" : "FALSE"); 1549 1550 fprintf(out, 1551 "#\n# TIMING AND THREADING OPTIONS\n#\n" 1552 "# Maximum number of SMPs sent in parallel\n" 1553 "max_wire_smps %u\n\n" 1554 "# The maximum time in [msec] allowed for a transaction to complete\n" 1555 "transaction_timeout %u\n\n" 1556 "# Maximal time in [msec] a message can stay in the incoming message queue.\n" 1557 "# If there is more than one message in the queue and the last message\n" 1558 "# stayed in the queue more than this value, any SA request will be\n" 1559 "# immediately returned with a BUSY status.\n" 1560 "max_msg_fifo_timeout %u\n\n" 1561 "# Use a single thread for handling SA queries\n" 1562 "single_thread %s\n\n", 1563 p_opts->max_wire_smps, 1564 p_opts->transaction_timeout, 1565 p_opts->max_msg_fifo_timeout, 1566 p_opts->single_thread ? "TRUE" : "FALSE"); 1567 1568 fprintf(out, 1569 "#\n# MISC OPTIONS\n#\n" 1570 "# Daemon mode\n" 1571 "daemon %s\n\n" 1572 "# SM Inactive\n" 1573 "sm_inactive %s\n\n" 1574 "# Babbling Port Policy\n" 1575 "babbling_port_policy %s\n\n", 1576 p_opts->daemon ? "TRUE" : "FALSE", 1577 p_opts->sm_inactive ? "TRUE" : "FALSE", 1578 p_opts->babbling_port_policy ? "TRUE" : "FALSE"); 1579 1580#ifdef ENABLE_OSM_PERF_MGR 1581 fprintf(out, 1582 "#\n# Performance Manager Options\n#\n" 1583 "# perfmgr enable\n" 1584 "perfmgr %s\n\n" 1585 "# perfmgr redirection enable\n" 1586 "perfmgr_redir %s\n\n" 1587 "# sweep time in seconds\n" 1588 "perfmgr_sweep_time_s %u\n\n" 1589 "# Max outstanding queries\n" 1590 "perfmgr_max_outstanding_queries %u\n\n", 1591 p_opts->perfmgr ? "TRUE" : "FALSE", 1592 p_opts->perfmgr_redir ? "TRUE" : "FALSE", 1593 p_opts->perfmgr_sweep_time_s, 1594 p_opts->perfmgr_max_outstanding_queries); 1595 1596 fprintf(out, 1597 "#\n# Event DB Options\n#\n" 1598 "# Dump file to dump the events to\n" 1599 "event_db_dump_file %s\n\n", p_opts->event_db_dump_file ? 1600 p_opts->event_db_dump_file : null_str); 1601#endif /* ENABLE_OSM_PERF_MGR */ 1602 1603 fprintf(out, 1604 "#\n# Event Plugin Options\n#\n" 1605 "event_plugin_name %s\n\n", p_opts->event_plugin_name ? 1606 p_opts->event_plugin_name : null_str); 1607 1608 fprintf(out, 1609 "#\n# Node name map for mapping node's to more descriptive node descriptions\n" 1610 "# (man ibnetdiscover for more information)\n#\n" 1611 "node_name_map_name %s\n\n", p_opts->node_name_map_name ? 1612 p_opts->node_name_map_name : null_str); 1613 1614 fprintf(out, 1615 "#\n# DEBUG FEATURES\n#\n" 1616 "# The log flags used\n" 1617 "log_flags 0x%02x\n\n" 1618 "# Force flush of the log file after each log message\n" 1619 "force_log_flush %s\n\n" 1620 "# Log file to be used\n" 1621 "log_file %s\n\n" 1622 "# Limit the size of the log file in MB. If overrun, log is restarted\n" 1623 "log_max_size %lu\n\n" 1624 "# If TRUE will accumulate the log over multiple OpenSM sessions\n" 1625 "accum_log_file %s\n\n" 1626 "# The directory to hold the file OpenSM dumps\n" 1627 "dump_files_dir %s\n\n" 1628 "# If TRUE enables new high risk options and hardware specific quirks\n" 1629 "enable_quirks %s\n\n" 1630 "# If TRUE disables client reregistration\n" 1631 "no_clients_rereg %s\n\n" 1632 "# If TRUE OpenSM should disable multicast support and\n" 1633 "# no multicast routing is performed if TRUE\n" 1634 "disable_multicast %s\n\n" 1635 "# If TRUE opensm will exit on fatal initialization issues\n" 1636 "exit_on_fatal %s\n\n" "# console [off|local" 1637#ifdef ENABLE_OSM_CONSOLE_SOCKET 1638 "|loopback|socket]\n" 1639#else 1640 "]\n" 1641#endif 1642 "console %s\n\n" 1643 "# Telnet port for console (default %d)\n" 1644 "console_port %d\n\n", 1645 p_opts->log_flags, 1646 p_opts->force_log_flush ? "TRUE" : "FALSE", 1647 p_opts->log_file, 1648 p_opts->log_max_size/1024/1024, 1649 p_opts->accum_log_file ? "TRUE" : "FALSE", 1650 p_opts->dump_files_dir, 1651 p_opts->enable_quirks ? "TRUE" : "FALSE", 1652 p_opts->no_clients_rereg ? "TRUE" : "FALSE", 1653 p_opts->disable_multicast ? "TRUE" : "FALSE", 1654 p_opts->exit_on_fatal ? "TRUE" : "FALSE", 1655 p_opts->console, 1656 OSM_DEFAULT_CONSOLE_PORT, p_opts->console_port); 1657 1658 fprintf(out, 1659 "#\n# QoS OPTIONS\n#\n" 1660 "# Enable QoS setup\n" 1661 "qos %s\n\n" 1662 "# QoS policy file to be used\n" 1663 "qos_policy_file %s\n\n", 1664 p_opts->qos ? "TRUE" : "FALSE", p_opts->qos_policy_file); 1665 1666 subn_dump_qos_options(out, 1667 "QoS default options", "qos", 1668 &p_opts->qos_options); 1669 fprintf(out, "\n"); 1670 subn_dump_qos_options(out, 1671 "QoS CA options", "qos_ca", 1672 &p_opts->qos_ca_options); 1673 fprintf(out, "\n"); 1674 subn_dump_qos_options(out, 1675 "QoS Switch Port 0 options", "qos_sw0", 1676 &p_opts->qos_sw0_options); 1677 fprintf(out, "\n"); 1678 subn_dump_qos_options(out, 1679 "QoS Switch external ports options", "qos_swe", 1680 &p_opts->qos_swe_options); 1681 fprintf(out, "\n"); 1682 subn_dump_qos_options(out, 1683 "QoS Router ports options", "qos_rtr", 1684 &p_opts->qos_rtr_options); 1685 fprintf(out, "\n"); 1686 1687 fprintf(out, 1688 "# Prefix routes file name\n" 1689 "prefix_routes_file %s\n\n", 1690 p_opts->prefix_routes_file); 1691 1692 fprintf(out, 1693 "#\n# IPv6 Solicited Node Multicast (SNM) Options\n#\n" 1694 "consolidate_ipv6_snm_req %s\n\n", 1695 p_opts->consolidate_ipv6_snm_req ? "TRUE" : "FALSE"); 1696 1697 /* optional string attributes ... */ 1698 1699 return 0; 1700} 1701 1702int osm_subn_write_conf_file(char *file_name, IN osm_subn_opt_t *const p_opts) 1703{ 1704 FILE *opts_file; 1705 1706 opts_file = fopen(file_name, "w"); 1707 if (!opts_file) { 1708 printf("cannot open file \'%s\' for writing: %s\n", 1709 file_name, strerror(errno)); 1710 return -1; 1711 } 1712 1713 if (osm_subn_output_conf(opts_file, p_opts) < 0) 1714 return -1; 1715 1716 fclose(opts_file); 1717 1718 return 0; 1719} 1720