osm_prtn.c revision 331769
1/* 2 * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2012 Mellanox Technologies LTD. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 * 33 */ 34 35/* 36 * Abstract: 37 * Implementation of osm_prtn_t. 38 * This object represents an IBA partition. 39 * This object is part of the opensm family of objects. 40 */ 41 42#if HAVE_CONFIG_H 43# include <config.h> 44#endif /* HAVE_CONFIG_H */ 45 46#include <stdlib.h> 47#include <string.h> 48#include <stdio.h> 49#include <sys/stat.h> 50#include <complib/cl_debug.h> 51#include <iba/ib_types.h> 52#include <opensm/osm_file_ids.h> 53#define FILE_ID OSM_FILE_PRTN_C 54#include <opensm/osm_opensm.h> 55#include <opensm/osm_partition.h> 56#include <opensm/osm_node.h> 57#include <opensm/osm_sa.h> 58#include <opensm/osm_multicast.h> 59#include <arpa/inet.h> 60#include <sys/socket.h> 61#include <errno.h> 62 63extern int osm_prtn_config_parse_file(osm_log_t * p_log, osm_subn_t * p_subn, 64 const char *file_name); 65 66static uint16_t global_pkey_counter; 67 68osm_prtn_t *osm_prtn_new(IN const char *name, IN uint16_t pkey) 69{ 70 osm_prtn_t *p = malloc(sizeof(*p)); 71 if (!p) 72 return NULL; 73 74 memset(p, 0, sizeof(*p)); 75 p->pkey = pkey; 76 p->sl = OSM_DEFAULT_SL; 77 p->mgrps = NULL; 78 p->nmgrps = 0; 79 cl_map_construct(&p->full_guid_tbl); 80 cl_map_init(&p->full_guid_tbl, 32); 81 cl_map_construct(&p->part_guid_tbl); 82 cl_map_init(&p->part_guid_tbl, 32); 83 84 if (name && *name) 85 strncpy(p->name, name, sizeof(p->name)); 86 else 87 snprintf(p->name, sizeof(p->name), "%04x", cl_ntoh16(pkey)); 88 89 return p; 90} 91 92void osm_prtn_delete(IN osm_subn_t * p_subn, IN OUT osm_prtn_t ** pp_prtn) 93{ 94 char gid_str[INET6_ADDRSTRLEN]; 95 int i = 0; 96 osm_prtn_t *p = *pp_prtn; 97 98 cl_map_remove_all(&p->full_guid_tbl); 99 cl_map_destroy(&p->full_guid_tbl); 100 cl_map_remove_all(&p->part_guid_tbl); 101 cl_map_destroy(&p->part_guid_tbl); 102 103 if (p->mgrps) { 104 /* Clean up mgrps */ 105 for (i = 0; i < p->nmgrps; i++) { 106 /* osm_mgrp_cleanup will not delete 107 * "well_known" groups */ 108 p->mgrps[i]->well_known = FALSE; 109 OSM_LOG(&p_subn->p_osm->log, OSM_LOG_DEBUG, 110 "removing mgroup %s from partition (0x%x)\n", 111 inet_ntop(AF_INET6, 112 p->mgrps[i]->mcmember_rec.mgid.raw, 113 gid_str, sizeof gid_str), 114 cl_hton16(p->pkey)); 115 osm_mgrp_cleanup(p_subn, p->mgrps[i]); 116 } 117 118 free(p->mgrps); 119 } 120 121 free(p); 122 *pp_prtn = NULL; 123} 124 125ib_api_status_t osm_prtn_add_port(osm_log_t * p_log, osm_subn_t * p_subn, 126 osm_prtn_t * p, ib_net64_t guid, 127 boolean_t full, boolean_t indx0) 128{ 129 ib_api_status_t status = IB_SUCCESS; 130 cl_map_t *p_tbl; 131 osm_port_t *p_port; 132 osm_physp_t *p_physp; 133 134 p_port = osm_get_port_by_guid(p_subn, guid); 135 if (!p_port) { 136 OSM_LOG(p_log, OSM_LOG_VERBOSE, 137 "port 0x%" PRIx64 " not found\n", cl_ntoh64(guid)); 138 return status; 139 } 140 141 p_physp = p_port->p_physp; 142 if (!p_physp) { 143 OSM_LOG(p_log, OSM_LOG_VERBOSE, 144 "no physical for port 0x%" PRIx64 "\n", 145 cl_ntoh64(guid)); 146 return status; 147 } 148 /* Set the pkey to be inserted to block 0 index 0 */ 149 if (indx0) { 150 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Setting pkey 0x%04x at indx0 " 151 "for port 0x%" PRIx64 "\n", 152 cl_ntoh16(p->pkey), cl_ntoh64(guid)); 153 osm_pkey_tbl_set_indx0_pkey(p_log, p->pkey, full, 154 &p_physp->pkeys); 155 } else if (ib_pkey_get_base(p_physp->pkeys.indx0_pkey) == 156 ib_pkey_get_base(p->pkey)) 157 p_physp->pkeys.indx0_pkey = 0; 158 159 p_tbl = (full == TRUE) ? &p->full_guid_tbl : &p->part_guid_tbl; 160 161 if (p_subn->opt.allow_both_pkeys) { 162 if (cl_map_remove(p_tbl, guid)) 163 OSM_LOG(p_log, OSM_LOG_VERBOSE, "port 0x%" PRIx64 164 " already in partition \'%s\' (0x%04x) full %d." 165 " Will overwrite\n", 166 cl_ntoh64(guid), p->name, cl_ntoh16(p->pkey), 167 full); 168 } else { 169 if (cl_map_remove(&p->part_guid_tbl, guid) || 170 cl_map_remove(&p->full_guid_tbl, guid)) 171 OSM_LOG(p_log, OSM_LOG_VERBOSE, "port 0x%" PRIx64 172 " already in partition \'%s\' (0x%04x)." 173 " Will overwrite\n", 174 cl_ntoh64(guid), p->name, cl_ntoh16(p->pkey)); 175 } 176 177 if (cl_map_insert(p_tbl, guid, p_physp) == NULL) 178 return IB_INSUFFICIENT_MEMORY; 179 180 return status; 181} 182 183ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, osm_subn_t * p_subn, 184 osm_prtn_t * p, unsigned type, 185 boolean_t full, boolean_t indx0) 186{ 187 cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl; 188 cl_map_item_t *p_item; 189 osm_port_t *p_port; 190 ib_api_status_t status = IB_SUCCESS; 191 192 p_item = cl_qmap_head(p_port_tbl); 193 while (p_item != cl_qmap_end(p_port_tbl)) { 194 p_port = (osm_port_t *) p_item; 195 p_item = cl_qmap_next(p_item); 196 if (!type || osm_node_get_type(p_port->p_node) == type) { 197 status = osm_prtn_add_port(p_log, p_subn, p, 198 osm_port_get_guid(p_port), 199 full, indx0); 200 if (status != IB_SUCCESS) 201 goto _err; 202 } 203 } 204 205_err: 206 return status; 207} 208 209static ib_api_status_t 210track_mgrp_w_partition(osm_log_t *p_log, osm_prtn_t *p, osm_mgrp_t *mgrp, 211 osm_subn_t *p_subn, const ib_gid_t *mgid, 212 ib_net16_t pkey) 213{ 214 char gid_str[INET6_ADDRSTRLEN]; 215 osm_mgrp_t **tmp; 216 int i = 0; 217 218 /* check if we are already tracking this group */ 219 for (i = 0; i < p->nmgrps; i++) 220 if (p->mgrps[i] == mgrp) 221 return (IB_SUCCESS); 222 223 /* otherwise add it to our list */ 224 tmp = realloc(p->mgrps, (p->nmgrps +1) * sizeof(*p->mgrps)); 225 if (tmp) { 226 p->mgrps = tmp; 227 p->mgrps[p->nmgrps] = mgrp; 228 p->nmgrps++; 229 } else { 230 OSM_LOG(p_log, OSM_LOG_ERROR, 231 "realloc error to create MC group (%s) in " 232 "partition (pkey 0x%04x)\n", 233 inet_ntop(AF_INET6, mgid->raw, 234 gid_str, sizeof gid_str), 235 cl_ntoh16(pkey)); 236 mgrp->well_known = FALSE; 237 osm_mgrp_cleanup(p_subn, mgrp); 238 return (IB_ERROR); 239 } 240 mgrp->well_known = TRUE; 241 return (IB_SUCCESS); 242} 243 244ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, osm_subn_t * p_subn, 245 osm_prtn_t * p, uint8_t rate, uint8_t mtu, 246 uint8_t sl, uint8_t scope, uint32_t Q_Key, 247 uint8_t tclass, uint32_t FlowLabel, 248 const ib_gid_t *mgid) 249{ 250 char gid_str[INET6_ADDRSTRLEN]; 251 ib_member_rec_t mc_rec; 252 ib_net64_t comp_mask; 253 ib_net16_t pkey; 254 osm_mgrp_t *mgrp; 255 osm_sa_t *p_sa = &p_subn->p_osm->sa; 256 uint8_t hop_limit; 257 258 pkey = p->pkey | cl_hton16(0x8000); 259 if (!scope) 260 scope = OSM_DEFAULT_MGRP_SCOPE; 261 hop_limit = (scope == IB_MC_SCOPE_LINK_LOCAL) ? 0 : IB_HOPLIMIT_MAX; 262 263 memset(&mc_rec, 0, sizeof(mc_rec)); 264 265 mc_rec.mgid = *mgid; 266 267 mc_rec.qkey = CL_HTON32(Q_Key); 268 mc_rec.mtu = mtu | (IB_PATH_SELECTOR_EXACTLY << 6); 269 mc_rec.tclass = tclass; 270 mc_rec.pkey = pkey; 271 mc_rec.rate = rate | (IB_PATH_SELECTOR_EXACTLY << 6); 272 mc_rec.pkt_life = p_subn->opt.subnet_timeout; 273 mc_rec.sl_flow_hop = ib_member_set_sl_flow_hop(sl, FlowLabel, hop_limit); 274 /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */ 275 mc_rec.scope_state = 276 ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER); 277 ib_mgid_set_scope(&mc_rec.mgid, scope); 278 279 /* don't update rate, mtu */ 280 comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL | 281 IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL; 282 mgrp = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec); 283 if (!mgrp) { 284 OSM_LOG(p_log, OSM_LOG_ERROR, 285 "Failed to create MC group (%s) with pkey 0x%04x\n", 286 inet_ntop(AF_INET6, mgid->raw, gid_str, sizeof gid_str), 287 cl_ntoh16(pkey)); 288 return IB_ERROR; 289 } 290 291 return (track_mgrp_w_partition(p_log, p, mgrp, p_subn, mgid, pkey)); 292} 293 294static uint16_t generate_pkey(osm_subn_t * p_subn) 295{ 296 uint16_t pkey; 297 298 cl_qmap_t *m = &p_subn->prtn_pkey_tbl; 299 while (global_pkey_counter < cl_ntoh16(IB_DEFAULT_PARTIAL_PKEY) - 1) { 300 pkey = ++global_pkey_counter; 301 pkey = cl_hton16(pkey); 302 if (cl_qmap_get(m, pkey) == cl_qmap_end(m)) 303 return pkey; 304 } 305 return 0; 306} 307 308osm_prtn_t *osm_prtn_find_by_name(osm_subn_t * p_subn, const char *name) 309{ 310 cl_map_item_t *p_next; 311 osm_prtn_t *p; 312 313 p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 314 while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 315 p = (osm_prtn_t *) p_next; 316 p_next = cl_qmap_next(&p->map_item); 317 if (!strncmp(p->name, name, sizeof(p->name))) 318 return p; 319 } 320 321 return NULL; 322} 323 324osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn, 325 const char *name, uint16_t pkey) 326{ 327 osm_prtn_t *p = NULL, *p_check; 328 329 pkey &= cl_hton16((uint16_t) ~ 0x8000); 330 if (!pkey) { 331 if (name && (p = osm_prtn_find_by_name(p_subn, name))) 332 return p; 333 if (!(pkey = generate_pkey(p_subn))) 334 return NULL; 335 } 336 337 p = osm_prtn_new(name, pkey); 338 if (!p) { 339 OSM_LOG(p_log, OSM_LOG_ERROR, "Unable to create" 340 " partition \'%s\' (0x%04x)\n", name, cl_ntoh16(pkey)); 341 return NULL; 342 } 343 344 p_check = (osm_prtn_t *) cl_qmap_insert(&p_subn->prtn_pkey_tbl, 345 p->pkey, &p->map_item); 346 if (p != p_check) { 347 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Duplicated partition" 348 " definition: \'%s\' (0x%04x) prev name \'%s\'" 349 ". Will use it\n", 350 name, cl_ntoh16(pkey), p_check->name); 351 osm_prtn_delete(p_subn, &p); 352 p = p_check; 353 } 354 355 return p; 356} 357 358static ib_api_status_t prtn_make_default(osm_log_t * p_log, osm_subn_t * p_subn, 359 boolean_t no_config) 360{ 361 ib_api_status_t status = IB_UNKNOWN_ERROR; 362 osm_prtn_t *p; 363 364 p = osm_prtn_make_new(p_log, p_subn, "Default", 365 IB_DEFAULT_PARTIAL_PKEY); 366 if (!p) 367 goto _err; 368 status = osm_prtn_add_all(p_log, p_subn, p, 0, no_config, FALSE); 369 if (status != IB_SUCCESS) 370 goto _err; 371 cl_map_remove(&p->part_guid_tbl, p_subn->sm_port_guid); 372 status = 373 osm_prtn_add_port(p_log, p_subn, p, p_subn->sm_port_guid, TRUE, FALSE); 374 375 /* ipv4 broadcast group */ 376 if (no_config) 377 osm_prtn_add_mcgroup(p_log, p_subn, p, OSM_DEFAULT_MGRP_RATE, 378 OSM_DEFAULT_MGRP_MTU, OSM_DEFAULT_SL, 379 0, OSM_IPOIB_BROADCAST_MGRP_QKEY, 0, 0, 380 &osm_ipoib_broadcast_mgid); 381 382_err: 383 return status; 384} 385 386ib_api_status_t osm_prtn_make_partitions(osm_log_t * p_log, osm_subn_t * p_subn) 387{ 388 struct stat statbuf; 389 const char *file_name; 390 boolean_t is_config = TRUE; 391 boolean_t is_wrong_config = FALSE; 392 ib_api_status_t status = IB_SUCCESS; 393 cl_map_item_t *p_next; 394 osm_prtn_t *p; 395 396 file_name = p_subn->opt.partition_config_file ? 397 p_subn->opt.partition_config_file : OSM_DEFAULT_PARTITION_CONFIG_FILE; 398 if (stat(file_name, &statbuf)) { 399 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Partition configuration " 400 "%s is not accessible (%s)\n", file_name, 401 strerror(errno)); 402 is_config = FALSE; 403 } 404 405retry_default: 406 /* clean up current port maps */ 407 p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 408 while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 409 p = (osm_prtn_t *) p_next; 410 p_next = cl_qmap_next(&p->map_item); 411 cl_map_remove_all(&p->part_guid_tbl); 412 cl_map_remove_all(&p->full_guid_tbl); 413 } 414 415 global_pkey_counter = 0; 416 417 status = prtn_make_default(p_log, p_subn, !is_config); 418 if (status != IB_SUCCESS) 419 goto _err; 420 421 if (is_config && osm_prtn_config_parse_file(p_log, p_subn, file_name)) { 422 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Partition configuration " 423 "was not fully processed\n"); 424 is_wrong_config = TRUE; 425 } 426 427 /* and now clean up empty partitions */ 428 p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); 429 while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { 430 p = (osm_prtn_t *) p_next; 431 p_next = cl_qmap_next(&p->map_item); 432 if (cl_map_count(&p->part_guid_tbl) == 0 && 433 cl_map_count(&p->full_guid_tbl) == 0) { 434 cl_qmap_remove_item(&p_subn->prtn_pkey_tbl, 435 (cl_map_item_t *) p); 436 osm_prtn_delete(p_subn, &p); 437 } 438 } 439 440 if (is_config && is_wrong_config) { 441 OSM_LOG(p_log, OSM_LOG_ERROR, "Partition configuration " 442 "in error; retrying with default config\n"); 443 is_config = FALSE; 444 goto retry_default; 445 } 446 447_err: 448 return status; 449} 450