1/* 2 * Copyright (c) 2006-2008 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 osm_prtn_t. 37 * This object represents an IBA partition. 38 * This object is part of the opensm family of objects. 39 */ 40 41#if HAVE_CONFIG_H 42# include <config.h> 43#endif /* HAVE_CONFIG_H */ 44 45#include <stdlib.h> 46#include <string.h> 47#include <stdio.h> 48#include <sys/stat.h> 49#include <complib/cl_debug.h> 50#include <iba/ib_types.h> 51#include <opensm/osm_opensm.h> 52#include <opensm/osm_partition.h> 53#include <opensm/osm_node.h> 54#include <opensm/osm_sa.h> 55#include <opensm/osm_multicast.h> 56 57extern int osm_prtn_config_parse_file(osm_log_t * const p_log, 58 osm_subn_t * const p_subn, 59 const char *file_name); 60 61static uint16_t global_pkey_counter; 62 63osm_prtn_t *osm_prtn_new(IN const char *name, IN const uint16_t pkey) 64{ 65 osm_prtn_t *p = malloc(sizeof(*p)); 66 if (!p) 67 return NULL; 68 69 memset(p, 0, sizeof(*p)); 70 p->pkey = pkey; 71 p->sl = OSM_DEFAULT_SL; 72 cl_map_construct(&p->full_guid_tbl); 73 cl_map_init(&p->full_guid_tbl, 32); 74 cl_map_construct(&p->part_guid_tbl); 75 cl_map_init(&p->part_guid_tbl, 32); 76 77 if (name && *name) 78 strncpy(p->name, name, sizeof(p->name)); 79 else 80 snprintf(p->name, sizeof(p->name), "%04x", cl_ntoh16(pkey)); 81 82 return p; 83} 84 85void osm_prtn_delete(IN OUT osm_prtn_t ** const pp_prtn) 86{ 87 osm_prtn_t *p = *pp_prtn; 88 89 cl_map_remove_all(&p->full_guid_tbl); 90 cl_map_destroy(&p->full_guid_tbl); 91 cl_map_remove_all(&p->part_guid_tbl); 92 cl_map_destroy(&p->part_guid_tbl); 93 free(p); 94 *pp_prtn = NULL; 95} 96 97ib_api_status_t osm_prtn_add_port(osm_log_t * p_log, osm_subn_t * p_subn, 98 osm_prtn_t * p, ib_net64_t guid, 99 boolean_t full) 100{ 101 ib_api_status_t status = IB_SUCCESS; 102 cl_map_t *p_tbl; 103 osm_port_t *p_port; 104 osm_physp_t *p_physp; 105 106 p_port = osm_get_port_by_guid(p_subn, guid); 107 if (!p_port) { 108 OSM_LOG(p_log, OSM_LOG_VERBOSE, 109 "port 0x%" PRIx64 " not found\n", cl_ntoh64(guid)); 110 return status; 111 } 112 113 p_physp = p_port->p_physp; 114 if (!p_physp) { 115 OSM_LOG(p_log, OSM_LOG_VERBOSE, 116 "no physical for port 0x%" PRIx64 "\n", 117 cl_ntoh64(guid)); 118 return status; 119 } 120 121 if (cl_map_remove(&p->part_guid_tbl, guid) || 122 cl_map_remove(&p->full_guid_tbl, guid)) { 123 OSM_LOG(p_log, OSM_LOG_VERBOSE, 124 "port 0x%" PRIx64 " already in " 125 "partition \'%s\' (0x%04x). Will overwrite\n", 126 cl_ntoh64(guid), p->name, cl_ntoh16(p->pkey)); 127 } 128 129 p_tbl = (full == TRUE) ? &p->full_guid_tbl : &p->part_guid_tbl; 130 131 if (cl_map_insert(p_tbl, guid, p_physp) == NULL) 132 return IB_INSUFFICIENT_MEMORY; 133 134 return status; 135} 136 137ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, osm_subn_t * p_subn, 138 osm_prtn_t * p, boolean_t full) 139{ 140 cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl; 141 cl_map_item_t *p_item; 142 osm_port_t *p_port; 143 ib_api_status_t status = IB_SUCCESS; 144 145 p_item = cl_qmap_head(p_port_tbl); 146 while (p_item != cl_qmap_end(p_port_tbl)) { 147 p_port = (osm_port_t *) p_item; 148 p_item = cl_qmap_next(p_item); 149 status = osm_prtn_add_port(p_log, p_subn, p, 150 osm_port_get_guid(p_port), full); 151 if (status != IB_SUCCESS) 152 goto _err; 153 } 154 155_err: 156 return status; 157} 158 159static const ib_gid_t osm_ipoib_mgid = { 160 { 161 0xff, /* multicast field */ 162 0x12, /* non-permanent bit, link local scope */ 163 0x40, 0x1b, /* IPv4 signature */ 164 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ 165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ 166 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */ 167 }, 168}; 169 170/* 171 * HACK: Until TS resolves their noncompliant join compmask, 172 * we have to pre-define the MGID 173 */ 174static const ib_gid_t osm_ts_ipoib_mgid = { 175 { 176 0xff, /* multicast field */ 177 0x12, /* non-permanent bit, link local scope */ 178 0x40, 0x1b, /* IPv4 signature */ 179 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ 180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ 181 0x00, 0x00, 0x00, 0x01, /* 32 bit IPv4 broadcast address */ 182 }, 183}; 184 185ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, 186 osm_subn_t * p_subn, osm_prtn_t * p, 187 uint8_t rate, 188 uint8_t mtu, uint8_t scope) 189{ 190 ib_member_rec_t mc_rec; 191 ib_net64_t comp_mask; 192 ib_net16_t pkey; 193 osm_mgrp_t *p_mgrp = NULL; 194 osm_sa_t *p_sa = &p_subn->p_osm->sa; 195 ib_api_status_t status = IB_SUCCESS; 196 uint8_t hop_limit; 197 198 pkey = p->pkey | cl_hton16(0x8000); 199 if (!scope) 200 scope = OSM_DEFAULT_MGRP_SCOPE; 201 hop_limit = (scope == IB_MC_SCOPE_LINK_LOCAL) ? 0 : IB_HOPLIMIT_MAX; 202 203 memset(&mc_rec, 0, sizeof(mc_rec)); 204 205 mc_rec.mgid = osm_ipoib_mgid; /* ipv4 broadcast group */ 206 memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey)); 207 208 mc_rec.qkey = CL_HTON32(0x0b1b); 209 mc_rec.mtu = (mtu ? mtu : OSM_DEFAULT_MGRP_MTU) | (2 << 6); /* 2048 Bytes */ 210 mc_rec.tclass = 0; 211 mc_rec.pkey = pkey; 212 mc_rec.rate = (rate ? rate : OSM_DEFAULT_MGRP_RATE) | (2 << 6); /* 10Gb/sec */ 213 mc_rec.pkt_life = p_subn->opt.subnet_timeout; 214 mc_rec.sl_flow_hop = ib_member_set_sl_flow_hop(p->sl, 0, hop_limit); 215 /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */ 216 mc_rec.scope_state = ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER); 217 ib_mgid_set_scope(&mc_rec.mgid, scope); 218 219 /* don't update rate, mtu */ 220 comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL | 221 IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL; 222 status = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec, 223 &p_mgrp); 224 if (!p_mgrp || status != IB_SUCCESS) 225 OSM_LOG(p_log, OSM_LOG_ERROR, 226 "Failed to create MC group with pkey 0x%04x\n", 227 cl_ntoh16(pkey)); 228 if (p_mgrp) { 229 p_mgrp->well_known = TRUE; 230 p->mlid = p_mgrp->mlid; 231 } 232 233 /* workaround for TS */ 234 /* FIXME: remove this upon TS fixes */ 235 mc_rec.mgid = osm_ts_ipoib_mgid; 236 memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey)); 237 /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */ 238 mc_rec.scope_state = ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER); 239 ib_mgid_set_scope(&mc_rec.mgid, scope); 240 241 status = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec, 242 &p_mgrp); 243 if (p_mgrp) { 244 p_mgrp->well_known = TRUE; 245 if (!p->mlid) 246 p->mlid = p_mgrp->mlid; 247 } 248 249 return status; 250} 251 252static uint16_t __generate_pkey(osm_subn_t * p_subn) 253{ 254 uint16_t pkey; 255 256 cl_qmap_t *m = &p_subn->prtn_pkey_tbl; 257 while (global_pkey_counter < cl_ntoh16(IB_DEFAULT_PARTIAL_PKEY) - 1) { 258 pkey = ++global_pkey_counter; 259 pkey = cl_hton16(pkey); 260 if (cl_qmap_get(m, pkey) == cl_qmap_end(m)) 261 return pkey; 262 } 263 return 0; 264} 265 266osm_prtn_t *osm_prtn_find_by_name(osm_subn_t * p_subn, const char *name) 267{ 268 cl_map_item_t *p_next; 269 osm_prtn_t *p; 270 271 p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 272 while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 273 p = (osm_prtn_t *) p_next; 274 p_next = cl_qmap_next(&p->map_item); 275 if (!strncmp(p->name, name, sizeof(p->name))) 276 return p; 277 } 278 279 return NULL; 280} 281 282osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn, 283 const char *name, uint16_t pkey) 284{ 285 osm_prtn_t *p = NULL, *p_check; 286 287 pkey &= cl_hton16((uint16_t) ~ 0x8000); 288 289 if (!pkey) { 290 if (name && (p = osm_prtn_find_by_name(p_subn, name))) 291 return p; 292 if (!(pkey = __generate_pkey(p_subn))) 293 return NULL; 294 } 295 296 p = osm_prtn_new(name, pkey); 297 if (!p) { 298 OSM_LOG(p_log, OSM_LOG_ERROR, "Unable to create" 299 " partition \'%s\' (0x%04x)\n", name, cl_ntoh16(pkey)); 300 return NULL; 301 } 302 303 p_check = (osm_prtn_t *) cl_qmap_insert(&p_subn->prtn_pkey_tbl, 304 p->pkey, &p->map_item); 305 if (p != p_check) { 306 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Duplicated partition" 307 " definition: \'%s\' (0x%04x) prev name \'%s\'" 308 ". Will use it\n", 309 name, cl_ntoh16(pkey), p_check->name); 310 osm_prtn_delete(&p); 311 p = p_check; 312 } 313 314 return p; 315} 316 317static ib_api_status_t osm_prtn_make_default(osm_log_t * const p_log, 318 osm_subn_t * const p_subn, 319 boolean_t no_config) 320{ 321 ib_api_status_t status = IB_UNKNOWN_ERROR; 322 osm_prtn_t *p; 323 324 p = osm_prtn_make_new(p_log, p_subn, "Default", 325 IB_DEFAULT_PARTIAL_PKEY); 326 if (!p) 327 goto _err; 328 status = osm_prtn_add_all(p_log, p_subn, p, no_config); 329 if (status != IB_SUCCESS) 330 goto _err; 331 cl_map_remove(&p->part_guid_tbl, p_subn->sm_port_guid); 332 status = 333 osm_prtn_add_port(p_log, p_subn, p, p_subn->sm_port_guid, TRUE); 334 335 if (no_config) 336 osm_prtn_add_mcgroup(p_log, p_subn, p, 0, 0, 0); 337 338_err: 339 return status; 340} 341 342ib_api_status_t osm_prtn_make_partitions(osm_log_t * const p_log, 343 osm_subn_t * const p_subn) 344{ 345 struct stat statbuf; 346 const char *file_name; 347 boolean_t is_config = TRUE; 348 ib_api_status_t status = IB_SUCCESS; 349 cl_map_item_t *p_next; 350 osm_prtn_t *p; 351 352 file_name = p_subn->opt.partition_config_file ? 353 p_subn->opt.partition_config_file : OSM_DEFAULT_PARTITION_CONFIG_FILE; 354 if (stat(file_name, &statbuf)) 355 is_config = FALSE; 356 357 /* clean up current port maps */ 358 p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 359 while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 360 p = (osm_prtn_t *) p_next; 361 p_next = cl_qmap_next(&p->map_item); 362 cl_map_remove_all(&p->part_guid_tbl); 363 cl_map_remove_all(&p->full_guid_tbl); 364 } 365 366 global_pkey_counter = 0; 367 368 status = osm_prtn_make_default(p_log, p_subn, !is_config); 369 if (status != IB_SUCCESS) 370 goto _err; 371 372 if (is_config && osm_prtn_config_parse_file(p_log, p_subn, file_name)) { 373 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Partition configuration " 374 "was not fully processed\n"); 375 } 376 377 /* and now clean up empty partitions */ 378 p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 379 while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 380 p = (osm_prtn_t *) p_next; 381 p_next = cl_qmap_next(&p->map_item); 382 if (cl_map_count(&p->part_guid_tbl) == 0 && 383 cl_map_count(&p->full_guid_tbl) == 0) { 384 cl_qmap_remove_item(&p_subn->prtn_pkey_tbl, 385 (cl_map_item_t *) p); 386 osm_prtn_delete(&p); 387 } 388 } 389 390_err: 391 return status; 392} 393