1219820Sjeff/* 2219820Sjeff * Copyright (c) 2006-2008 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 osm_prtn_t. 37219820Sjeff * This object represents an IBA partition. 38219820Sjeff * This object is part of the opensm family of objects. 39219820Sjeff */ 40219820Sjeff 41219820Sjeff#if HAVE_CONFIG_H 42219820Sjeff# include <config.h> 43219820Sjeff#endif /* HAVE_CONFIG_H */ 44219820Sjeff 45219820Sjeff#include <stdlib.h> 46219820Sjeff#include <string.h> 47219820Sjeff#include <stdio.h> 48219820Sjeff#include <sys/stat.h> 49219820Sjeff#include <complib/cl_debug.h> 50219820Sjeff#include <iba/ib_types.h> 51219820Sjeff#include <opensm/osm_opensm.h> 52219820Sjeff#include <opensm/osm_partition.h> 53219820Sjeff#include <opensm/osm_node.h> 54219820Sjeff#include <opensm/osm_sa.h> 55219820Sjeff#include <opensm/osm_multicast.h> 56219820Sjeff 57219820Sjeffextern int osm_prtn_config_parse_file(osm_log_t * const p_log, 58219820Sjeff osm_subn_t * const p_subn, 59219820Sjeff const char *file_name); 60219820Sjeff 61219820Sjeffstatic uint16_t global_pkey_counter; 62219820Sjeff 63219820Sjeffosm_prtn_t *osm_prtn_new(IN const char *name, IN const uint16_t pkey) 64219820Sjeff{ 65219820Sjeff osm_prtn_t *p = malloc(sizeof(*p)); 66219820Sjeff if (!p) 67219820Sjeff return NULL; 68219820Sjeff 69219820Sjeff memset(p, 0, sizeof(*p)); 70219820Sjeff p->pkey = pkey; 71219820Sjeff p->sl = OSM_DEFAULT_SL; 72219820Sjeff cl_map_construct(&p->full_guid_tbl); 73219820Sjeff cl_map_init(&p->full_guid_tbl, 32); 74219820Sjeff cl_map_construct(&p->part_guid_tbl); 75219820Sjeff cl_map_init(&p->part_guid_tbl, 32); 76219820Sjeff 77219820Sjeff if (name && *name) 78219820Sjeff strncpy(p->name, name, sizeof(p->name)); 79219820Sjeff else 80219820Sjeff snprintf(p->name, sizeof(p->name), "%04x", cl_ntoh16(pkey)); 81219820Sjeff 82219820Sjeff return p; 83219820Sjeff} 84219820Sjeff 85219820Sjeffvoid osm_prtn_delete(IN OUT osm_prtn_t ** const pp_prtn) 86219820Sjeff{ 87219820Sjeff osm_prtn_t *p = *pp_prtn; 88219820Sjeff 89219820Sjeff cl_map_remove_all(&p->full_guid_tbl); 90219820Sjeff cl_map_destroy(&p->full_guid_tbl); 91219820Sjeff cl_map_remove_all(&p->part_guid_tbl); 92219820Sjeff cl_map_destroy(&p->part_guid_tbl); 93219820Sjeff free(p); 94219820Sjeff *pp_prtn = NULL; 95219820Sjeff} 96219820Sjeff 97219820Sjeffib_api_status_t osm_prtn_add_port(osm_log_t * p_log, osm_subn_t * p_subn, 98219820Sjeff osm_prtn_t * p, ib_net64_t guid, 99219820Sjeff boolean_t full) 100219820Sjeff{ 101219820Sjeff ib_api_status_t status = IB_SUCCESS; 102219820Sjeff cl_map_t *p_tbl; 103219820Sjeff osm_port_t *p_port; 104219820Sjeff osm_physp_t *p_physp; 105219820Sjeff 106219820Sjeff p_port = osm_get_port_by_guid(p_subn, guid); 107219820Sjeff if (!p_port) { 108219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 109219820Sjeff "port 0x%" PRIx64 " not found\n", cl_ntoh64(guid)); 110219820Sjeff return status; 111219820Sjeff } 112219820Sjeff 113219820Sjeff p_physp = p_port->p_physp; 114219820Sjeff if (!p_physp) { 115219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 116219820Sjeff "no physical for port 0x%" PRIx64 "\n", 117219820Sjeff cl_ntoh64(guid)); 118219820Sjeff return status; 119219820Sjeff } 120219820Sjeff 121219820Sjeff if (cl_map_remove(&p->part_guid_tbl, guid) || 122219820Sjeff cl_map_remove(&p->full_guid_tbl, guid)) { 123219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 124219820Sjeff "port 0x%" PRIx64 " already in " 125219820Sjeff "partition \'%s\' (0x%04x). Will overwrite\n", 126219820Sjeff cl_ntoh64(guid), p->name, cl_ntoh16(p->pkey)); 127219820Sjeff } 128219820Sjeff 129219820Sjeff p_tbl = (full == TRUE) ? &p->full_guid_tbl : &p->part_guid_tbl; 130219820Sjeff 131219820Sjeff if (cl_map_insert(p_tbl, guid, p_physp) == NULL) 132219820Sjeff return IB_INSUFFICIENT_MEMORY; 133219820Sjeff 134219820Sjeff return status; 135219820Sjeff} 136219820Sjeff 137219820Sjeffib_api_status_t osm_prtn_add_all(osm_log_t * p_log, osm_subn_t * p_subn, 138219820Sjeff osm_prtn_t * p, boolean_t full) 139219820Sjeff{ 140219820Sjeff cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl; 141219820Sjeff cl_map_item_t *p_item; 142219820Sjeff osm_port_t *p_port; 143219820Sjeff ib_api_status_t status = IB_SUCCESS; 144219820Sjeff 145219820Sjeff p_item = cl_qmap_head(p_port_tbl); 146219820Sjeff while (p_item != cl_qmap_end(p_port_tbl)) { 147219820Sjeff p_port = (osm_port_t *) p_item; 148219820Sjeff p_item = cl_qmap_next(p_item); 149219820Sjeff status = osm_prtn_add_port(p_log, p_subn, p, 150219820Sjeff osm_port_get_guid(p_port), full); 151219820Sjeff if (status != IB_SUCCESS) 152219820Sjeff goto _err; 153219820Sjeff } 154219820Sjeff 155219820Sjeff_err: 156219820Sjeff return status; 157219820Sjeff} 158219820Sjeff 159219820Sjeffstatic const ib_gid_t osm_ipoib_mgid = { 160219820Sjeff { 161219820Sjeff 0xff, /* multicast field */ 162219820Sjeff 0x12, /* non-permanent bit, link local scope */ 163219820Sjeff 0x40, 0x1b, /* IPv4 signature */ 164219820Sjeff 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ 165219820Sjeff 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ 166219820Sjeff 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */ 167219820Sjeff }, 168219820Sjeff}; 169219820Sjeff 170219820Sjeff/* 171219820Sjeff * HACK: Until TS resolves their noncompliant join compmask, 172219820Sjeff * we have to pre-define the MGID 173219820Sjeff */ 174219820Sjeffstatic const ib_gid_t osm_ts_ipoib_mgid = { 175219820Sjeff { 176219820Sjeff 0xff, /* multicast field */ 177219820Sjeff 0x12, /* non-permanent bit, link local scope */ 178219820Sjeff 0x40, 0x1b, /* IPv4 signature */ 179219820Sjeff 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ 180219820Sjeff 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ 181219820Sjeff 0x00, 0x00, 0x00, 0x01, /* 32 bit IPv4 broadcast address */ 182219820Sjeff }, 183219820Sjeff}; 184219820Sjeff 185219820Sjeffib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, 186219820Sjeff osm_subn_t * p_subn, osm_prtn_t * p, 187219820Sjeff uint8_t rate, 188219820Sjeff uint8_t mtu, uint8_t scope) 189219820Sjeff{ 190219820Sjeff ib_member_rec_t mc_rec; 191219820Sjeff ib_net64_t comp_mask; 192219820Sjeff ib_net16_t pkey; 193219820Sjeff osm_mgrp_t *p_mgrp = NULL; 194219820Sjeff osm_sa_t *p_sa = &p_subn->p_osm->sa; 195219820Sjeff ib_api_status_t status = IB_SUCCESS; 196219820Sjeff uint8_t hop_limit; 197219820Sjeff 198219820Sjeff pkey = p->pkey | cl_hton16(0x8000); 199219820Sjeff if (!scope) 200219820Sjeff scope = OSM_DEFAULT_MGRP_SCOPE; 201219820Sjeff hop_limit = (scope == IB_MC_SCOPE_LINK_LOCAL) ? 0 : IB_HOPLIMIT_MAX; 202219820Sjeff 203219820Sjeff memset(&mc_rec, 0, sizeof(mc_rec)); 204219820Sjeff 205219820Sjeff mc_rec.mgid = osm_ipoib_mgid; /* ipv4 broadcast group */ 206219820Sjeff memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey)); 207219820Sjeff 208219820Sjeff mc_rec.qkey = CL_HTON32(0x0b1b); 209219820Sjeff mc_rec.mtu = (mtu ? mtu : OSM_DEFAULT_MGRP_MTU) | (2 << 6); /* 2048 Bytes */ 210219820Sjeff mc_rec.tclass = 0; 211219820Sjeff mc_rec.pkey = pkey; 212219820Sjeff mc_rec.rate = (rate ? rate : OSM_DEFAULT_MGRP_RATE) | (2 << 6); /* 10Gb/sec */ 213219820Sjeff mc_rec.pkt_life = p_subn->opt.subnet_timeout; 214219820Sjeff mc_rec.sl_flow_hop = ib_member_set_sl_flow_hop(p->sl, 0, hop_limit); 215219820Sjeff /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */ 216219820Sjeff mc_rec.scope_state = ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER); 217219820Sjeff ib_mgid_set_scope(&mc_rec.mgid, scope); 218219820Sjeff 219219820Sjeff /* don't update rate, mtu */ 220219820Sjeff comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL | 221219820Sjeff IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL; 222219820Sjeff status = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec, 223219820Sjeff &p_mgrp); 224219820Sjeff if (!p_mgrp || status != IB_SUCCESS) 225219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, 226219820Sjeff "Failed to create MC group with pkey 0x%04x\n", 227219820Sjeff cl_ntoh16(pkey)); 228219820Sjeff if (p_mgrp) { 229219820Sjeff p_mgrp->well_known = TRUE; 230219820Sjeff p->mlid = p_mgrp->mlid; 231219820Sjeff } 232219820Sjeff 233219820Sjeff /* workaround for TS */ 234219820Sjeff /* FIXME: remove this upon TS fixes */ 235219820Sjeff mc_rec.mgid = osm_ts_ipoib_mgid; 236219820Sjeff memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey)); 237219820Sjeff /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */ 238219820Sjeff mc_rec.scope_state = ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER); 239219820Sjeff ib_mgid_set_scope(&mc_rec.mgid, scope); 240219820Sjeff 241219820Sjeff status = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec, 242219820Sjeff &p_mgrp); 243219820Sjeff if (p_mgrp) { 244219820Sjeff p_mgrp->well_known = TRUE; 245219820Sjeff if (!p->mlid) 246219820Sjeff p->mlid = p_mgrp->mlid; 247219820Sjeff } 248219820Sjeff 249219820Sjeff return status; 250219820Sjeff} 251219820Sjeff 252219820Sjeffstatic uint16_t __generate_pkey(osm_subn_t * p_subn) 253219820Sjeff{ 254219820Sjeff uint16_t pkey; 255219820Sjeff 256219820Sjeff cl_qmap_t *m = &p_subn->prtn_pkey_tbl; 257219820Sjeff while (global_pkey_counter < cl_ntoh16(IB_DEFAULT_PARTIAL_PKEY) - 1) { 258219820Sjeff pkey = ++global_pkey_counter; 259219820Sjeff pkey = cl_hton16(pkey); 260219820Sjeff if (cl_qmap_get(m, pkey) == cl_qmap_end(m)) 261219820Sjeff return pkey; 262219820Sjeff } 263219820Sjeff return 0; 264219820Sjeff} 265219820Sjeff 266219820Sjeffosm_prtn_t *osm_prtn_find_by_name(osm_subn_t * p_subn, const char *name) 267219820Sjeff{ 268219820Sjeff cl_map_item_t *p_next; 269219820Sjeff osm_prtn_t *p; 270219820Sjeff 271219820Sjeff p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 272219820Sjeff while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 273219820Sjeff p = (osm_prtn_t *) p_next; 274219820Sjeff p_next = cl_qmap_next(&p->map_item); 275219820Sjeff if (!strncmp(p->name, name, sizeof(p->name))) 276219820Sjeff return p; 277219820Sjeff } 278219820Sjeff 279219820Sjeff return NULL; 280219820Sjeff} 281219820Sjeff 282219820Sjeffosm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn, 283219820Sjeff const char *name, uint16_t pkey) 284219820Sjeff{ 285219820Sjeff osm_prtn_t *p = NULL, *p_check; 286219820Sjeff 287219820Sjeff pkey &= cl_hton16((uint16_t) ~ 0x8000); 288219820Sjeff 289219820Sjeff if (!pkey) { 290219820Sjeff if (name && (p = osm_prtn_find_by_name(p_subn, name))) 291219820Sjeff return p; 292219820Sjeff if (!(pkey = __generate_pkey(p_subn))) 293219820Sjeff return NULL; 294219820Sjeff } 295219820Sjeff 296219820Sjeff p = osm_prtn_new(name, pkey); 297219820Sjeff if (!p) { 298219820Sjeff OSM_LOG(p_log, OSM_LOG_ERROR, "Unable to create" 299219820Sjeff " partition \'%s\' (0x%04x)\n", name, cl_ntoh16(pkey)); 300219820Sjeff return NULL; 301219820Sjeff } 302219820Sjeff 303219820Sjeff p_check = (osm_prtn_t *) cl_qmap_insert(&p_subn->prtn_pkey_tbl, 304219820Sjeff p->pkey, &p->map_item); 305219820Sjeff if (p != p_check) { 306219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, "Duplicated partition" 307219820Sjeff " definition: \'%s\' (0x%04x) prev name \'%s\'" 308219820Sjeff ". Will use it\n", 309219820Sjeff name, cl_ntoh16(pkey), p_check->name); 310219820Sjeff osm_prtn_delete(&p); 311219820Sjeff p = p_check; 312219820Sjeff } 313219820Sjeff 314219820Sjeff return p; 315219820Sjeff} 316219820Sjeff 317219820Sjeffstatic ib_api_status_t osm_prtn_make_default(osm_log_t * const p_log, 318219820Sjeff osm_subn_t * const p_subn, 319219820Sjeff boolean_t no_config) 320219820Sjeff{ 321219820Sjeff ib_api_status_t status = IB_UNKNOWN_ERROR; 322219820Sjeff osm_prtn_t *p; 323219820Sjeff 324219820Sjeff p = osm_prtn_make_new(p_log, p_subn, "Default", 325219820Sjeff IB_DEFAULT_PARTIAL_PKEY); 326219820Sjeff if (!p) 327219820Sjeff goto _err; 328219820Sjeff status = osm_prtn_add_all(p_log, p_subn, p, no_config); 329219820Sjeff if (status != IB_SUCCESS) 330219820Sjeff goto _err; 331219820Sjeff cl_map_remove(&p->part_guid_tbl, p_subn->sm_port_guid); 332219820Sjeff status = 333219820Sjeff osm_prtn_add_port(p_log, p_subn, p, p_subn->sm_port_guid, TRUE); 334219820Sjeff 335219820Sjeff if (no_config) 336219820Sjeff osm_prtn_add_mcgroup(p_log, p_subn, p, 0, 0, 0); 337219820Sjeff 338219820Sjeff_err: 339219820Sjeff return status; 340219820Sjeff} 341219820Sjeff 342219820Sjeffib_api_status_t osm_prtn_make_partitions(osm_log_t * const p_log, 343219820Sjeff osm_subn_t * const p_subn) 344219820Sjeff{ 345219820Sjeff struct stat statbuf; 346219820Sjeff const char *file_name; 347219820Sjeff boolean_t is_config = TRUE; 348219820Sjeff ib_api_status_t status = IB_SUCCESS; 349219820Sjeff cl_map_item_t *p_next; 350219820Sjeff osm_prtn_t *p; 351219820Sjeff 352219820Sjeff file_name = p_subn->opt.partition_config_file ? 353219820Sjeff p_subn->opt.partition_config_file : OSM_DEFAULT_PARTITION_CONFIG_FILE; 354219820Sjeff if (stat(file_name, &statbuf)) 355219820Sjeff is_config = FALSE; 356219820Sjeff 357219820Sjeff /* clean up current port maps */ 358219820Sjeff p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 359219820Sjeff while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 360219820Sjeff p = (osm_prtn_t *) p_next; 361219820Sjeff p_next = cl_qmap_next(&p->map_item); 362219820Sjeff cl_map_remove_all(&p->part_guid_tbl); 363219820Sjeff cl_map_remove_all(&p->full_guid_tbl); 364219820Sjeff } 365219820Sjeff 366219820Sjeff global_pkey_counter = 0; 367219820Sjeff 368219820Sjeff status = osm_prtn_make_default(p_log, p_subn, !is_config); 369219820Sjeff if (status != IB_SUCCESS) 370219820Sjeff goto _err; 371219820Sjeff 372219820Sjeff if (is_config && osm_prtn_config_parse_file(p_log, p_subn, file_name)) { 373219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, "Partition configuration " 374219820Sjeff "was not fully processed\n"); 375219820Sjeff } 376219820Sjeff 377219820Sjeff /* and now clean up empty partitions */ 378219820Sjeff p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 379219820Sjeff while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 380219820Sjeff p = (osm_prtn_t *) p_next; 381219820Sjeff p_next = cl_qmap_next(&p->map_item); 382219820Sjeff if (cl_map_count(&p->part_guid_tbl) == 0 && 383219820Sjeff cl_map_count(&p->full_guid_tbl) == 0) { 384219820Sjeff cl_qmap_remove_item(&p_subn->prtn_pkey_tbl, 385219820Sjeff (cl_map_item_t *) p); 386219820Sjeff osm_prtn_delete(&p); 387219820Sjeff } 388219820Sjeff } 389219820Sjeff 390219820Sjeff_err: 391219820Sjeff return status; 392219820Sjeff} 393