1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5219820Sjeff * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. 6219820Sjeff * 7219820Sjeff * This software is available to you under a choice of one of two 8219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 9219820Sjeff * General Public License (GPL) Version 2, available from the file 10219820Sjeff * COPYING in the main directory of this source tree, or the 11219820Sjeff * OpenIB.org BSD license below: 12219820Sjeff * 13219820Sjeff * Redistribution and use in source and binary forms, with or 14219820Sjeff * without modification, are permitted provided that the following 15219820Sjeff * conditions are met: 16219820Sjeff * 17219820Sjeff * - Redistributions of source code must retain the above 18219820Sjeff * copyright notice, this list of conditions and the following 19219820Sjeff * disclaimer. 20219820Sjeff * 21219820Sjeff * - Redistributions in binary form must reproduce the above 22219820Sjeff * copyright notice, this list of conditions and the following 23219820Sjeff * disclaimer in the documentation and/or other materials 24219820Sjeff * provided with the distribution. 25219820Sjeff * 26219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33219820Sjeff * SOFTWARE. 34219820Sjeff * 35219820Sjeff */ 36219820Sjeff 37219820Sjeff/* 38219820Sjeff * Abstract: 39219820Sjeff * Implementation of osm_mcmr_recv_t. 40219820Sjeff * This object represents the MCMemberRecord Receiver object. 41219820Sjeff * This object is part of the opensm family of objects. 42219820Sjeff */ 43219820Sjeff 44219820Sjeff#if HAVE_CONFIG_H 45219820Sjeff# include <config.h> 46219820Sjeff#endif /* HAVE_CONFIG_H */ 47219820Sjeff 48219820Sjeff#include <stdlib.h> 49219820Sjeff#include <string.h> 50219820Sjeff#include <arpa/inet.h> 51219820Sjeff#include <iba/ib_types.h> 52219820Sjeff#include <complib/cl_qmap.h> 53219820Sjeff#include <complib/cl_passivelock.h> 54219820Sjeff#include <complib/cl_debug.h> 55219820Sjeff#include <complib/cl_qlist.h> 56219820Sjeff#include <vendor/osm_vendor_api.h> 57219820Sjeff#include <opensm/osm_madw.h> 58219820Sjeff#include <opensm/osm_log.h> 59219820Sjeff#include <opensm/osm_subnet.h> 60219820Sjeff#include <opensm/osm_mad_pool.h> 61219820Sjeff#include <opensm/osm_helper.h> 62219820Sjeff#include <opensm/osm_msgdef.h> 63219820Sjeff#include <opensm/osm_pkey.h> 64219820Sjeff#include <opensm/osm_inform.h> 65219820Sjeff#include <opensm/osm_sa.h> 66219820Sjeff 67219820Sjeff#include <sys/socket.h> 68219820Sjeff 69219820Sjeff#define JOIN_MC_COMP_MASK (IB_MCR_COMPMASK_MGID | \ 70219820Sjeff IB_MCR_COMPMASK_PORT_GID | \ 71219820Sjeff IB_MCR_COMPMASK_JOIN_STATE) 72219820Sjeff 73219820Sjeff#define REQUIRED_MC_CREATE_COMP_MASK (IB_MCR_COMPMASK_MGID | \ 74219820Sjeff IB_MCR_COMPMASK_PORT_GID | \ 75219820Sjeff IB_MCR_COMPMASK_JOIN_STATE | \ 76219820Sjeff IB_MCR_COMPMASK_QKEY | \ 77219820Sjeff IB_MCR_COMPMASK_TCLASS | \ 78219820Sjeff IB_MCR_COMPMASK_PKEY | \ 79219820Sjeff IB_MCR_COMPMASK_FLOW | \ 80219820Sjeff IB_MCR_COMPMASK_SL) 81219820Sjeff 82219820Sjefftypedef struct osm_mcmr_item { 83219820Sjeff cl_list_item_t list_item; 84219820Sjeff ib_member_rec_t rec; 85219820Sjeff} osm_mcmr_item_t; 86219820Sjeff 87219820Sjeff/********************************************************************* 88219820Sjeff Copy certain fields between two mcmember records 89219820Sjeff used during the process of join request to copy data from the mgrp 90219820Sjeff to the port record. 91219820Sjeff**********************************************************************/ 92219820Sjeffstatic inline void 93219820Sjeff__copy_from_create_mc_rec(IN ib_member_rec_t * const dest, 94219820Sjeff IN const ib_member_rec_t * const src) 95219820Sjeff{ 96219820Sjeff dest->qkey = src->qkey; 97219820Sjeff dest->mlid = src->mlid; 98219820Sjeff dest->tclass = src->tclass; 99219820Sjeff dest->pkey = src->pkey; 100219820Sjeff dest->sl_flow_hop = src->sl_flow_hop; 101219820Sjeff dest->mtu = src->mtu; 102219820Sjeff dest->rate = src->rate; 103219820Sjeff dest->pkt_life = src->pkt_life; 104219820Sjeff} 105219820Sjeff 106219820Sjeff/********************************************************************* 107219820Sjeff Return mlid to the pool of free mlids. 108219820Sjeff But this implementation is not a pool - it simply scans through 109219820Sjeff the MGRP database for unused mlids... 110219820Sjeff*********************************************************************/ 111219820Sjeffstatic void __free_mlid(IN osm_sa_t * sa, IN uint16_t mlid) 112219820Sjeff{ 113219820Sjeff UNUSED_PARAM(sa); 114219820Sjeff UNUSED_PARAM(mlid); 115219820Sjeff} 116219820Sjeff 117219820Sjeff/********************************************************************* 118219820Sjeff Get a new unused mlid by scanning all the used ones in the subnet. 119219820Sjeff**********************************************************************/ 120219820Sjeffstatic ib_net16_t __get_new_mlid(osm_sa_t *sa, ib_net16_t requested_mlid) 121219820Sjeff{ 122219820Sjeff osm_subn_t *p_subn = sa->p_subn; 123219820Sjeff unsigned i, max; 124219820Sjeff 125219820Sjeff if (requested_mlid && cl_ntoh16(requested_mlid) >= IB_LID_MCAST_START_HO 126219820Sjeff && cl_ntoh16(requested_mlid) <= p_subn->max_mcast_lid_ho 127219820Sjeff && !osm_get_mgrp_by_mlid(p_subn, requested_mlid)) 128219820Sjeff return requested_mlid; 129219820Sjeff 130219820Sjeff max = p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO + 1; 131219820Sjeff for (i = 0; i < max; i++) { 132219820Sjeff osm_mgrp_t *p_mgrp = sa->p_subn->mgroups[i]; 133219820Sjeff if (!p_mgrp || p_mgrp->to_be_deleted) 134219820Sjeff return cl_hton16(i + IB_LID_MCAST_START_HO); 135219820Sjeff } 136219820Sjeff 137219820Sjeff return 0; 138219820Sjeff} 139219820Sjeff 140219820Sjeff/********************************************************************* 141219820Sjeff This procedure is only invoked to cleanup an INTERMEDIATE mgrp. 142219820Sjeff If there is only one port on the mgrp it means that the current 143219820Sjeff request was the only member and the group is not really needed. So 144219820Sjeff we silently drop it. Since it was an intermediate group no need to 145219820Sjeff re-route it. 146219820Sjeff**********************************************************************/ 147219820Sjeffstatic void __cleanup_mgrp(IN osm_sa_t * sa, osm_mgrp_t *mgrp) 148219820Sjeff{ 149219820Sjeff /* Remove MGRP only if osm_mcm_port_t count is 0 and 150219820Sjeff not a well known group */ 151219820Sjeff if (cl_is_qmap_empty(&mgrp->mcm_port_tbl) && !mgrp->well_known) { 152219820Sjeff sa->p_subn->mgroups[cl_ntoh16(mgrp->mlid) - IB_LID_MCAST_START_HO] = NULL; 153219820Sjeff osm_mgrp_delete(mgrp); 154219820Sjeff } 155219820Sjeff} 156219820Sjeff 157219820Sjeff/********************************************************************* 158219820Sjeff Add a port to the group. Calculating its PROXY_JOIN by the Port and 159219820Sjeff requester gids. 160219820Sjeff**********************************************************************/ 161219820Sjeffstatic ib_api_status_t 162219820Sjeff__add_new_mgrp_port(IN osm_sa_t * sa, 163219820Sjeff IN osm_mgrp_t * p_mgrp, 164219820Sjeff IN ib_member_rec_t * p_recvd_mcmember_rec, 165219820Sjeff IN osm_mad_addr_t * p_mad_addr, 166219820Sjeff OUT osm_mcm_port_t ** pp_mcmr_port) 167219820Sjeff{ 168219820Sjeff boolean_t proxy_join; 169219820Sjeff ib_gid_t requester_gid; 170219820Sjeff ib_api_status_t res; 171219820Sjeff 172219820Sjeff /* set the proxy_join if the requester gid is not identical to the 173219820Sjeff joined gid */ 174219820Sjeff res = osm_get_gid_by_mad_addr(sa->p_log, sa->p_subn, 175219820Sjeff p_mad_addr, &requester_gid); 176219820Sjeff if (res != IB_SUCCESS) { 177219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B29: " 178219820Sjeff "Could not find GID for requester\n"); 179219820Sjeff 180219820Sjeff return IB_INVALID_PARAMETER; 181219820Sjeff } 182219820Sjeff 183219820Sjeff if (!memcmp(&p_recvd_mcmember_rec->port_gid, &requester_gid, 184219820Sjeff sizeof(ib_gid_t))) { 185219820Sjeff proxy_join = FALSE; 186219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 187219820Sjeff "Create new port with proxy_join FALSE\n"); 188219820Sjeff } else { 189219820Sjeff /* The port is not the one specified in PortGID. 190219820Sjeff The check that the requester is in the same partition as 191219820Sjeff the PortGID is done before - just need to update 192219820Sjeff the proxy_join. */ 193219820Sjeff proxy_join = TRUE; 194219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 195219820Sjeff "Create new port with proxy_join TRUE\n"); 196219820Sjeff } 197219820Sjeff 198219820Sjeff *pp_mcmr_port = osm_mgrp_add_port(sa->p_subn, sa->p_log, p_mgrp, 199219820Sjeff &p_recvd_mcmember_rec->port_gid, 200219820Sjeff p_recvd_mcmember_rec->scope_state, 201219820Sjeff proxy_join); 202219820Sjeff if (*pp_mcmr_port == NULL) { 203219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B06: " 204219820Sjeff "osm_mgrp_add_port failed\n"); 205219820Sjeff 206219820Sjeff return IB_INSUFFICIENT_MEMORY; 207219820Sjeff } 208219820Sjeff 209219820Sjeff return IB_SUCCESS; 210219820Sjeff} 211219820Sjeff 212219820Sjeff/********************************************************************** 213219820Sjeff **********************************************************************/ 214219820Sjeffstatic inline boolean_t __check_join_comp_mask(ib_net64_t comp_mask) 215219820Sjeff{ 216219820Sjeff return ((comp_mask & JOIN_MC_COMP_MASK) == JOIN_MC_COMP_MASK); 217219820Sjeff} 218219820Sjeff 219219820Sjeff/********************************************************************** 220219820Sjeff **********************************************************************/ 221219820Sjeffstatic inline boolean_t 222219820Sjeff__check_create_comp_mask(ib_net64_t comp_mask, 223219820Sjeff ib_member_rec_t * p_recvd_mcmember_rec) 224219820Sjeff{ 225219820Sjeff return ((comp_mask & REQUIRED_MC_CREATE_COMP_MASK) == 226219820Sjeff REQUIRED_MC_CREATE_COMP_MASK); 227219820Sjeff} 228219820Sjeff 229219820Sjeff/********************************************************************** 230219820Sjeff Generate the response MAD 231219820Sjeff**********************************************************************/ 232219820Sjeffstatic void 233219820Sjeff__osm_mcmr_rcv_respond(IN osm_sa_t * sa, 234219820Sjeff IN osm_madw_t * const p_madw, 235219820Sjeff IN ib_member_rec_t * p_mcmember_rec) 236219820Sjeff{ 237219820Sjeff cl_qlist_t rec_list; 238219820Sjeff osm_mcmr_item_t *item; 239219820Sjeff 240219820Sjeff OSM_LOG_ENTER(sa->p_log); 241219820Sjeff 242219820Sjeff item = malloc(sizeof(*item)); 243219820Sjeff if (!item) { 244219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B16: " 245219820Sjeff "rec_item alloc failed\n"); 246219820Sjeff goto Exit; 247219820Sjeff } 248219820Sjeff 249219820Sjeff item->rec = *p_mcmember_rec; 250219820Sjeff 251219820Sjeff /* Fill in the mtu, rate, and packet lifetime selectors */ 252219820Sjeff item->rec.mtu &= 0x3f; 253219820Sjeff item->rec.mtu |= 2 << 6; /* exactly */ 254219820Sjeff item->rec.rate &= 0x3f; 255219820Sjeff item->rec.rate |= 2 << 6; /* exactly */ 256219820Sjeff item->rec.pkt_life &= 0x3f; 257219820Sjeff item->rec.pkt_life |= 2 << 6; /* exactly */ 258219820Sjeff 259219820Sjeff cl_qlist_init(&rec_list); 260219820Sjeff cl_qlist_insert_tail(&rec_list, &item->list_item); 261219820Sjeff 262219820Sjeff osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list); 263219820Sjeff 264219820SjeffExit: 265219820Sjeff OSM_LOG_EXIT(sa->p_log); 266219820Sjeff} 267219820Sjeff 268219820Sjeff/********************************************************************* 269219820Sjeff In joining an existing group, or when querying the mc groups, 270219820Sjeff we make sure the following components provided match: MTU and RATE 271219820Sjeff HACK: Currently we ignore the PKT_LIFETIME field. 272219820Sjeff**********************************************************************/ 273219820Sjeffstatic boolean_t 274219820Sjeff__validate_more_comp_fields(osm_log_t * p_log, 275219820Sjeff const osm_mgrp_t * p_mgrp, 276219820Sjeff const ib_member_rec_t * p_recvd_mcmember_rec, 277219820Sjeff ib_net64_t comp_mask) 278219820Sjeff{ 279219820Sjeff uint8_t mtu_sel; 280219820Sjeff uint8_t mtu_required; 281219820Sjeff uint8_t mtu_mgrp; 282219820Sjeff uint8_t rate_sel; 283219820Sjeff uint8_t rate_required; 284219820Sjeff uint8_t rate_mgrp; 285219820Sjeff 286219820Sjeff if (comp_mask & IB_MCR_COMPMASK_MTU_SEL) { 287219820Sjeff mtu_sel = (uint8_t) (p_recvd_mcmember_rec->mtu >> 6); 288219820Sjeff /* Clearing last 2 bits */ 289219820Sjeff mtu_required = (uint8_t) (p_recvd_mcmember_rec->mtu & 0x3F); 290219820Sjeff mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F); 291219820Sjeff switch (mtu_sel) { 292219820Sjeff case 0: /* Greater than MTU specified */ 293219820Sjeff if (mtu_mgrp <= mtu_required) { 294219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 295219820Sjeff "Requested mcast group has MTU %x, " 296219820Sjeff "which is not greater than %x\n", 297219820Sjeff mtu_mgrp, mtu_required); 298219820Sjeff return FALSE; 299219820Sjeff } 300219820Sjeff break; 301219820Sjeff case 1: /* Less than MTU specified */ 302219820Sjeff if (mtu_mgrp >= mtu_required) { 303219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 304219820Sjeff "Requested mcast group has MTU %x, " 305219820Sjeff "which is not less than %x\n", 306219820Sjeff mtu_mgrp, mtu_required); 307219820Sjeff return FALSE; 308219820Sjeff } 309219820Sjeff break; 310219820Sjeff case 2: /* Exactly MTU specified */ 311219820Sjeff if (mtu_mgrp != mtu_required) { 312219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 313219820Sjeff "Requested mcast group has MTU %x, " 314219820Sjeff "which is not equal to %x\n", 315219820Sjeff mtu_mgrp, mtu_required); 316219820Sjeff return FALSE; 317219820Sjeff } 318219820Sjeff break; 319219820Sjeff default: 320219820Sjeff break; 321219820Sjeff } 322219820Sjeff } 323219820Sjeff 324219820Sjeff /* what about rate ? */ 325219820Sjeff if (comp_mask & IB_MCR_COMPMASK_RATE_SEL) { 326219820Sjeff rate_sel = (uint8_t) (p_recvd_mcmember_rec->rate >> 6); 327219820Sjeff /* Clearing last 2 bits */ 328219820Sjeff rate_required = (uint8_t) (p_recvd_mcmember_rec->rate & 0x3F); 329219820Sjeff rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F); 330219820Sjeff switch (rate_sel) { 331219820Sjeff case 0: /* Greater than RATE specified */ 332219820Sjeff if (rate_mgrp <= rate_required) { 333219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 334219820Sjeff "Requested mcast group has RATE %x, " 335219820Sjeff "which is not greater than %x\n", 336219820Sjeff rate_mgrp, rate_required); 337219820Sjeff return FALSE; 338219820Sjeff } 339219820Sjeff break; 340219820Sjeff case 1: /* Less than RATE specified */ 341219820Sjeff if (rate_mgrp >= rate_required) { 342219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 343219820Sjeff "Requested mcast group has RATE %x, " 344219820Sjeff "which is not less than %x\n", 345219820Sjeff rate_mgrp, rate_required); 346219820Sjeff return FALSE; 347219820Sjeff } 348219820Sjeff break; 349219820Sjeff case 2: /* Exactly RATE specified */ 350219820Sjeff if (rate_mgrp != rate_required) { 351219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 352219820Sjeff "Requested mcast group has RATE %x, " 353219820Sjeff "which is not equal to %x\n", 354219820Sjeff rate_mgrp, rate_required); 355219820Sjeff return FALSE; 356219820Sjeff } 357219820Sjeff break; 358219820Sjeff default: 359219820Sjeff break; 360219820Sjeff } 361219820Sjeff } 362219820Sjeff 363219820Sjeff return TRUE; 364219820Sjeff} 365219820Sjeff 366219820Sjeff/********************************************************************* 367219820Sjeff In joining an existing group, we make sure the following components 368219820Sjeff are physically realizable: MTU and RATE 369219820Sjeff**********************************************************************/ 370219820Sjeffstatic boolean_t 371219820Sjeff__validate_port_caps(osm_log_t * const p_log, 372219820Sjeff const osm_mgrp_t * p_mgrp, const osm_physp_t * p_physp) 373219820Sjeff{ 374219820Sjeff uint8_t mtu_required; 375219820Sjeff uint8_t mtu_mgrp; 376219820Sjeff uint8_t rate_required; 377219820Sjeff uint8_t rate_mgrp; 378219820Sjeff 379219820Sjeff mtu_required = ib_port_info_get_mtu_cap(&p_physp->port_info); 380219820Sjeff mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F); 381219820Sjeff if (mtu_required < mtu_mgrp) { 382219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 383219820Sjeff "Port's MTU %x is less than %x\n", 384219820Sjeff mtu_required, mtu_mgrp); 385219820Sjeff return FALSE; 386219820Sjeff } 387219820Sjeff 388219820Sjeff rate_required = ib_port_info_compute_rate(&p_physp->port_info); 389219820Sjeff rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F); 390219820Sjeff if (rate_required < rate_mgrp) { 391219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 392219820Sjeff "Port's RATE %x is less than %x\n", 393219820Sjeff rate_required, rate_mgrp); 394219820Sjeff return FALSE; 395219820Sjeff } 396219820Sjeff 397219820Sjeff return TRUE; 398219820Sjeff} 399219820Sjeff 400219820Sjeff/********************************************************************** 401219820Sjeff * o15-0.2.1: If SA supports UD multicast, then if SA receives a SubnAdmSet() 402219820Sjeff * or SubnAdmDelete() method that would modify an existing 403219820Sjeff * MCMemberRecord, SA shall not modify that MCMemberRecord and shall 404219820Sjeff * return an error status of ERR_REQ_INVALID in response in the 405219820Sjeff * following cases: 406219820Sjeff * 1. Saved MCMemberRecord.ProxyJoin is not set and the request is 407219820Sjeff * issued by a requester with a GID other than the Port-GID. 408219820Sjeff * 2. Saved MCMemberRecord.ProxyJoin is set and the requester is not 409219820Sjeff * part of the partition for that MCMemberRecord. 410219820Sjeff **********************************************************************/ 411219820Sjeffstatic boolean_t 412219820Sjeff__validate_modify(IN osm_sa_t * sa, 413219820Sjeff IN osm_mgrp_t * p_mgrp, 414219820Sjeff IN osm_mad_addr_t * p_mad_addr, 415219820Sjeff IN ib_member_rec_t * p_recvd_mcmember_rec, 416219820Sjeff OUT osm_mcm_port_t ** pp_mcm_port) 417219820Sjeff{ 418219820Sjeff ib_net64_t portguid; 419219820Sjeff ib_gid_t request_gid; 420219820Sjeff osm_physp_t *p_request_physp; 421219820Sjeff ib_api_status_t res; 422219820Sjeff 423219820Sjeff portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; 424219820Sjeff 425219820Sjeff *pp_mcm_port = NULL; 426219820Sjeff 427219820Sjeff /* o15-0.2.1: If this is a new port being added - nothing to check */ 428219820Sjeff if (!osm_mgrp_is_port_present(p_mgrp, portguid, pp_mcm_port)) { 429219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 430219820Sjeff "This is a new port in the MC group\n"); 431219820Sjeff return TRUE; 432219820Sjeff } 433219820Sjeff 434219820Sjeff /* We validate the request according the the proxy_join. 435219820Sjeff Check if the proxy_join is set or not */ 436219820Sjeff if ((*pp_mcm_port)->proxy_join == FALSE) { 437219820Sjeff /* The proxy_join is not set. Modifying can by done only 438219820Sjeff if the requester GID == PortGID */ 439219820Sjeff res = osm_get_gid_by_mad_addr(sa->p_log, 440219820Sjeff sa->p_subn, 441219820Sjeff p_mad_addr, &request_gid); 442219820Sjeff 443219820Sjeff if (res != IB_SUCCESS) { 444219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 445219820Sjeff "Could not find port for requested address\n"); 446219820Sjeff return FALSE; 447219820Sjeff } 448219820Sjeff 449219820Sjeff if (memcmp(&((*pp_mcm_port)->port_gid), &request_gid, 450219820Sjeff sizeof(ib_gid_t))) { 451219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 452219820Sjeff "No ProxyJoin but different ports: stored:" 453219820Sjeff "0x%016" PRIx64 " request:0x%016" PRIx64 "\n", 454219820Sjeff cl_ntoh64((*pp_mcm_port)->port_gid.unicast. 455219820Sjeff interface_id), 456219820Sjeff cl_ntoh64(p_mad_addr->addr_type.gsi.grh_info. 457219820Sjeff src_gid.unicast.interface_id)); 458219820Sjeff return FALSE; 459219820Sjeff } 460219820Sjeff } else { 461219820Sjeff /* The proxy_join is set. Modification allowed only if the 462219820Sjeff requester is part of the partition for this MCMemberRecord */ 463219820Sjeff p_request_physp = osm_get_physp_by_mad_addr(sa->p_log, 464219820Sjeff sa->p_subn, 465219820Sjeff p_mad_addr); 466219820Sjeff if (p_request_physp == NULL) 467219820Sjeff return FALSE; 468219820Sjeff 469219820Sjeff if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey, 470219820Sjeff p_request_physp)) { 471219820Sjeff /* the request port is not part of the partition for this mgrp */ 472219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 473219820Sjeff "ProxyJoin but port not in partition. stored:" 474219820Sjeff "0x%016" PRIx64 " request:0x%016" PRIx64 "\n", 475219820Sjeff cl_ntoh64((*pp_mcm_port)->port_gid.unicast. 476219820Sjeff interface_id), 477219820Sjeff cl_ntoh64(p_mad_addr->addr_type.gsi.grh_info. 478219820Sjeff src_gid.unicast.interface_id)); 479219820Sjeff return FALSE; 480219820Sjeff } 481219820Sjeff } 482219820Sjeff return TRUE; 483219820Sjeff} 484219820Sjeff 485219820Sjeff/********************************************************************** 486219820Sjeff **********************************************************************/ 487219820Sjeff/* 488219820Sjeff * Check legality of the requested MGID DELETE 489219820Sjeff * o15-0.1.14 = VALID DELETE: 490219820Sjeff * To be a valid delete MAD needs to: 491219820Sjeff * 1 the MADs PortGID and MGID components match the PortGID and 492219820Sjeff * MGID of a stored MCMemberRecord; 493219820Sjeff * 2 the MADs JoinState component contains at least one bit set to 1 494219820Sjeff * in the same position as that stored MCMemberRecords JoinState 495219820Sjeff * has a bit set to 1, 496219820Sjeff * i.e., the logical AND of the two JoinState components 497219820Sjeff * is not all zeros; 498219820Sjeff * 3 the MADs JoinState component does not have some bits set 499219820Sjeff * which are not set in the stored MCMemberRecords JoinState component; 500219820Sjeff * 4 either the stored MCMemberRecord:ProxyJoin is reset (0), and the 501219820Sjeff * MADs source is the stored PortGID; 502219820Sjeff * OR 503219820Sjeff * the stored MCMemberRecord:ProxyJoin is set (1), (see o15- 504219820Sjeff * 0.1.2:); and the MADs source is a member of the partition indicated 505219820Sjeff * by the stored MCMemberRecord:P_Key. 506219820Sjeff */ 507219820Sjeffstatic boolean_t 508219820Sjeff__validate_delete(IN osm_sa_t * sa, 509219820Sjeff IN osm_mgrp_t * p_mgrp, 510219820Sjeff IN osm_mad_addr_t * p_mad_addr, 511219820Sjeff IN ib_member_rec_t * p_recvd_mcmember_rec, 512219820Sjeff OUT osm_mcm_port_t ** pp_mcm_port) 513219820Sjeff{ 514219820Sjeff ib_net64_t portguid; 515219820Sjeff 516219820Sjeff portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; 517219820Sjeff 518219820Sjeff *pp_mcm_port = NULL; 519219820Sjeff 520219820Sjeff /* 1 */ 521219820Sjeff if (!osm_mgrp_is_port_present(p_mgrp, portguid, pp_mcm_port)) { 522219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 523219820Sjeff "Failed to find the port in the MC group\n"); 524219820Sjeff return FALSE; 525219820Sjeff } 526219820Sjeff 527219820Sjeff /* 2 */ 528219820Sjeff if (!(p_recvd_mcmember_rec->scope_state & 0x0F & 529219820Sjeff (*pp_mcm_port)->scope_state)) { 530219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 531219820Sjeff "Could not find any matching bits in the stored " 532219820Sjeff "and requested JoinStates\n"); 533219820Sjeff return FALSE; 534219820Sjeff } 535219820Sjeff 536219820Sjeff /* 3 */ 537219820Sjeff if (((p_recvd_mcmember_rec->scope_state & 0x0F) | 538219820Sjeff (0x0F & (*pp_mcm_port)->scope_state)) != 539219820Sjeff (0x0F & (*pp_mcm_port)->scope_state)) { 540219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 541219820Sjeff "Some bits in the request JoinState (0x%X) are not " 542219820Sjeff "set in the stored port (0x%X)\n", 543219820Sjeff (p_recvd_mcmember_rec->scope_state & 0x0F), 544219820Sjeff (0x0F & (*pp_mcm_port)->scope_state)); 545219820Sjeff return FALSE; 546219820Sjeff } 547219820Sjeff 548219820Sjeff /* 4 */ 549219820Sjeff /* Validate according the the proxy_join (o15-0.1.2) */ 550219820Sjeff if (__validate_modify(sa, p_mgrp, p_mad_addr, p_recvd_mcmember_rec, 551219820Sjeff pp_mcm_port) == FALSE) { 552219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 553219820Sjeff "proxy_join validation failure\n"); 554219820Sjeff return FALSE; 555219820Sjeff } 556219820Sjeff return TRUE; 557219820Sjeff} 558219820Sjeff 559219820Sjeff/********************************************************************** 560219820Sjeff **********************************************************************/ 561219820Sjeff/* 562219820Sjeff * Check legality of the requested MGID (note this does not hold for SA 563219820Sjeff * created MGIDs) 564219820Sjeff * 565219820Sjeff * Implementing o15-0.1.5: 566219820Sjeff * A multicast GID is considered to be invalid if: 567219820Sjeff * 1. It does not comply with the rules as specified in 4.1.1 "GID Usage and 568219820Sjeff * Properties" on page 145: 569219820Sjeff * 570219820Sjeff * 14) The multicast GID format is (bytes are comma sep): 571219820Sjeff * 0xff,<Fl><Sc>,<Si>,<Si>,<P>,<P>,<P>,<P>,<P>,<P>,<P>,<P>,<Id>,<Id>,<Id>,<Id> 572219820Sjeff * Fl 4bit = Flags (b) 573219820Sjeff * Sc 4bit = Scope (c) 574219820Sjeff * Si 16bit = Signature (2) 575219820Sjeff * P 64bit = GID Prefix (should be a subnet unique ID - normally Subnet Prefix) 576219820Sjeff * Id 32bit = Unique ID in the Subnet (might be MLID or Pkey ?) 577219820Sjeff * 578219820Sjeff * a) 8-bits of 11111111 at the start of the GID identifies this as being a 579219820Sjeff * multicast GID. 580219820Sjeff * b) Flags is a set of four 1-bit flags: 000T with three flags reserved 581219820Sjeff * and defined as zero (0). The T flag is defined as follows: 582219820Sjeff * i) T = 0 indicates this is a permanently assigned (i.e. wellknown) 583219820Sjeff * multicast GID. See RFC 2373 and RFC 2375 as reference 584219820Sjeff * for these permanently assigned GIDs. 585219820Sjeff * ii) T = 1 indicates this is a non-permanently assigned (i.e. transient) 586219820Sjeff * multicast GID. 587219820Sjeff * c) Scope is a 4-bit multicast scope value used to limit the scope of 588219820Sjeff * the multicast group. The following table defines scope value and 589219820Sjeff * interpretation. 590219820Sjeff * 591219820Sjeff * Multicast Address Scope Values: 592219820Sjeff * 0x2 Link-local 593219820Sjeff * 0x5 Site-local 594219820Sjeff * 0x8 Organization-local 595219820Sjeff * 0xE Global 596219820Sjeff * 597219820Sjeff * 2. It contains the SA-specific signature of 0xA01B and has the link-local 598219820Sjeff * scope bits set. (EZ: the idea here is that SA created MGIDs are the 599219820Sjeff * only source for this signature with link-local scope) 600219820Sjeff */ 601219820Sjeffstatic ib_api_status_t 602219820Sjeff__validate_requested_mgid(IN osm_sa_t * sa, 603219820Sjeff IN const ib_member_rec_t * p_mcm_rec) 604219820Sjeff{ 605219820Sjeff uint16_t signature; 606219820Sjeff boolean_t valid = TRUE; 607219820Sjeff 608219820Sjeff OSM_LOG_ENTER(sa->p_log); 609219820Sjeff 610219820Sjeff /* 14-a: mcast GID must start with 0xFF */ 611219820Sjeff if (p_mcm_rec->mgid.multicast.header[0] != 0xFF) { 612219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B01: " 613219820Sjeff "Wrong MGID Prefix 0x%02X must be 0xFF\n", 614219820Sjeff cl_ntoh16(p_mcm_rec->mgid.multicast.header[0])); 615219820Sjeff valid = FALSE; 616219820Sjeff goto Exit; 617219820Sjeff } 618219820Sjeff 619219820Sjeff /* the MGID signature can mark IPoIB or SA assigned MGIDs */ 620219820Sjeff memcpy(&signature, &(p_mcm_rec->mgid.multicast.raw_group_id), 621219820Sjeff sizeof(signature)); 622219820Sjeff signature = cl_ntoh16(signature); 623219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 624219820Sjeff "MGID Signed as 0x%04X\n", signature); 625219820Sjeff 626219820Sjeff /* 627219820Sjeff * We skip any checks for MGIDs that follow IPoIB 628219820Sjeff * GID structure as defined by the IETF ipoib-link-multicast. 629219820Sjeff * 630219820Sjeff * For IPv4 over IB, the signature will be "0x401B". 631219820Sjeff * 632219820Sjeff * | 8 | 4 | 4 | 16 bits | 16 bits | 48 bits | 32 bits | 633219820Sjeff * +--------+----+----+-----------------+---------+----------+---------+ 634219820Sjeff * |11111111|0001|scop|<IPoIB signature>|< P_Key >|00.......0|<all 1's>| 635219820Sjeff * +--------+----+----+-----------------+---------+----------+---------+ 636219820Sjeff * 637219820Sjeff * For IPv6 over IB, the signature will be "0x601B". 638219820Sjeff * 639219820Sjeff * | 8 | 4 | 4 | 16 bits | 16 bits | 80 bits | 640219820Sjeff * +--------+----+----+-----------------+---------+--------------------+ 641219820Sjeff * |11111111|0001|scop|<IPoIB signature>|< P_Key >|000.............0001| 642219820Sjeff * +--------+----+----+-----------------+---------+--------------------+ 643219820Sjeff * 644219820Sjeff */ 645219820Sjeff if (signature == 0x401B || signature == 0x601B) { 646219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 647219820Sjeff "Skipping MGID Validation for IPoIB Signed (0x%04X) MGIDs\n", 648219820Sjeff signature); 649219820Sjeff goto Exit; 650219820Sjeff } 651219820Sjeff 652219820Sjeff /* 14-b: the 3 upper bits in the "flags" should be zero: */ 653219820Sjeff if (p_mcm_rec->mgid.multicast.header[1] & 0xE0) { 654219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B28: " 655219820Sjeff "MGID uses Reserved Flags: flags=0x%X\n", 656219820Sjeff (p_mcm_rec->mgid.multicast.header[1] & 0xE0) >> 4); 657219820Sjeff valid = FALSE; 658219820Sjeff goto Exit; 659219820Sjeff } 660219820Sjeff 661219820Sjeff /* 2 - now what if the link local format 0xA01B is used - 662219820Sjeff the scope should not be link local */ 663219820Sjeff if (signature == 0xA01B && 664219820Sjeff (p_mcm_rec->mgid.multicast.header[1] & 0x0F) == 665219820Sjeff IB_MC_SCOPE_LINK_LOCAL) { 666219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B24: " 667219820Sjeff "MGID uses 0xA01B signature but with link-local scope\n"); 668219820Sjeff valid = FALSE; 669219820Sjeff goto Exit; 670219820Sjeff } 671219820Sjeff 672219820Sjeff /* 673219820Sjeff * For SA assigned MGIDs (signature 0xA01B): 674219820Sjeff * There is no real way to make sure the Unique MGID Prefix is really unique. 675219820Sjeff * If we could enforce using the Subnet Prefix for that purpose it would 676219820Sjeff * have been nice. But the spec does not require it. 677219820Sjeff */ 678219820Sjeff 679219820SjeffExit: 680219820Sjeff OSM_LOG_EXIT(sa->p_log); 681219820Sjeff return (valid); 682219820Sjeff} 683219820Sjeff 684219820Sjeff/********************************************************************** 685219820Sjeff Check if the requested new MC group parameters are realizable. 686219820Sjeff Also set the default MTU and Rate if not provided by the user. 687219820Sjeff**********************************************************************/ 688219820Sjeffstatic boolean_t 689219820Sjeff__mgrp_request_is_realizable(IN osm_sa_t * sa, 690219820Sjeff IN ib_net64_t comp_mask, 691219820Sjeff IN ib_member_rec_t * p_mcm_rec, 692219820Sjeff IN const osm_physp_t * const p_physp) 693219820Sjeff{ 694219820Sjeff uint8_t mtu_sel = 2; /* exactly */ 695219820Sjeff uint8_t mtu_required, mtu, port_mtu; 696219820Sjeff uint8_t rate_sel = 2; /* exactly */ 697219820Sjeff uint8_t rate_required, rate, port_rate; 698219820Sjeff osm_log_t *p_log = sa->p_log; 699219820Sjeff 700219820Sjeff OSM_LOG_ENTER(sa->p_log); 701219820Sjeff 702219820Sjeff /* 703219820Sjeff * End of o15-0.2.3 specifies: 704219820Sjeff * .... 705219820Sjeff * The entity may also supply the other components such as HopLimit, 706219820Sjeff * MTU, etc. during group creation time. If these components are not 707219820Sjeff * provided during group creation time, SA will provide them for the 708219820Sjeff * group. The values chosen are vendor-dependent and beyond the scope 709219820Sjeff * of the specification. 710219820Sjeff * 711219820Sjeff * so we might also need to assign RATE/MTU if they are not comp 712219820Sjeff * masked in. 713219820Sjeff */ 714219820Sjeff 715219820Sjeff port_mtu = p_physp ? ib_port_info_get_mtu_cap(&p_physp->port_info) : 0; 716219820Sjeff if (!(comp_mask & IB_MCR_COMPMASK_MTU) || 717219820Sjeff !(comp_mask & IB_MCR_COMPMASK_MTU_SEL) || 718219820Sjeff (mtu_sel = (p_mcm_rec->mtu >> 6)) == 3) 719219820Sjeff mtu = port_mtu ? port_mtu : sa->p_subn->min_ca_mtu; 720219820Sjeff else { 721219820Sjeff mtu_required = (uint8_t) (p_mcm_rec->mtu & 0x3F); 722219820Sjeff mtu = mtu_required; 723219820Sjeff switch (mtu_sel) { 724219820Sjeff case 0: /* Greater than MTU specified */ 725219820Sjeff if (port_mtu && mtu_required >= port_mtu) { 726219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 727219820Sjeff "Requested MTU %x >= the port\'s mtu:%x\n", 728219820Sjeff mtu_required, port_mtu); 729219820Sjeff return FALSE; 730219820Sjeff } 731219820Sjeff /* we provide the largest MTU possible if we can */ 732219820Sjeff if (port_mtu) 733219820Sjeff mtu = port_mtu; 734219820Sjeff else if (mtu_required < sa->p_subn->min_ca_mtu) 735219820Sjeff mtu = sa->p_subn->min_ca_mtu; 736219820Sjeff else 737219820Sjeff mtu++; 738219820Sjeff break; 739219820Sjeff case 1: /* Less than MTU specified */ 740219820Sjeff /* use the smaller of the two: 741219820Sjeff a. one lower then the required 742219820Sjeff b. the mtu of the requesting port (if exists) */ 743219820Sjeff if (port_mtu && mtu_required > port_mtu) 744219820Sjeff mtu = port_mtu; 745219820Sjeff else 746219820Sjeff mtu--; 747219820Sjeff break; 748219820Sjeff case 2: /* Exactly MTU specified */ 749219820Sjeff default: 750219820Sjeff break; 751219820Sjeff } 752219820Sjeff /* make sure it still be in the range */ 753219820Sjeff if (mtu < IB_MIN_MTU || mtu > IB_MAX_MTU) { 754219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 755219820Sjeff "Calculated MTU %x is out of range\n", mtu); 756219820Sjeff return FALSE; 757219820Sjeff } 758219820Sjeff } 759219820Sjeff p_mcm_rec->mtu = (mtu_sel << 6) | mtu; 760219820Sjeff 761219820Sjeff port_rate = 762219820Sjeff p_physp ? ib_port_info_compute_rate(&p_physp->port_info) : 0; 763219820Sjeff if (!(comp_mask & IB_MCR_COMPMASK_RATE) 764219820Sjeff || !(comp_mask & IB_MCR_COMPMASK_RATE_SEL) 765219820Sjeff || (rate_sel = (p_mcm_rec->rate >> 6)) == 3) 766219820Sjeff rate = port_rate ? port_rate : sa->p_subn->min_ca_rate; 767219820Sjeff else { 768219820Sjeff rate_required = (uint8_t) (p_mcm_rec->rate & 0x3F); 769219820Sjeff rate = rate_required; 770219820Sjeff switch (rate_sel) { 771219820Sjeff case 0: /* Greater than RATE specified */ 772219820Sjeff if (port_rate && rate_required >= port_rate) { 773219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 774219820Sjeff "Requested RATE %x >= the port\'s rate:%x\n", 775219820Sjeff rate_required, port_rate); 776219820Sjeff return FALSE; 777219820Sjeff } 778219820Sjeff /* we provide the largest RATE possible if we can */ 779219820Sjeff if (port_rate) 780219820Sjeff rate = port_rate; 781219820Sjeff else if (rate_required < sa->p_subn->min_ca_rate) 782219820Sjeff rate = sa->p_subn->min_ca_rate; 783219820Sjeff else 784219820Sjeff rate++; 785219820Sjeff break; 786219820Sjeff case 1: /* Less than RATE specified */ 787219820Sjeff /* use the smaller of the two: 788219820Sjeff a. one lower then the required 789219820Sjeff b. the rate of the requesting port (if exists) */ 790219820Sjeff if (port_rate && rate_required > port_rate) 791219820Sjeff rate = port_rate; 792219820Sjeff else 793219820Sjeff rate--; 794219820Sjeff break; 795219820Sjeff case 2: /* Exactly RATE specified */ 796219820Sjeff default: 797219820Sjeff break; 798219820Sjeff } 799219820Sjeff /* make sure it still is in the range */ 800219820Sjeff if (rate < IB_MIN_RATE || rate > IB_MAX_RATE) { 801219820Sjeff OSM_LOG(p_log, OSM_LOG_DEBUG, 802219820Sjeff "Calculated RATE %x is out of range\n", rate); 803219820Sjeff return FALSE; 804219820Sjeff } 805219820Sjeff } 806219820Sjeff p_mcm_rec->rate = (rate_sel << 6) | rate; 807219820Sjeff 808219820Sjeff OSM_LOG_EXIT(sa->p_log); 809219820Sjeff return TRUE; 810219820Sjeff} 811219820Sjeff 812219820Sjeff/********************************************************************** 813219820Sjeff Call this function to create a new mgrp. 814219820Sjeff**********************************************************************/ 815219820Sjeffib_api_status_t 816219820Sjeffosm_mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa, 817219820Sjeff IN ib_net64_t comp_mask, 818219820Sjeff IN const ib_member_rec_t * 819219820Sjeff const p_recvd_mcmember_rec, 820219820Sjeff IN const osm_physp_t * const p_physp, 821219820Sjeff OUT osm_mgrp_t ** pp_mgrp) 822219820Sjeff{ 823219820Sjeff ib_net16_t mlid; 824219820Sjeff unsigned zero_mgid, i; 825219820Sjeff uint8_t scope; 826219820Sjeff ib_gid_t *p_mgid; 827219820Sjeff osm_mgrp_t *p_prev_mgrp; 828219820Sjeff ib_api_status_t status = IB_SUCCESS; 829219820Sjeff ib_member_rec_t mcm_rec = *p_recvd_mcmember_rec; /* copy for modifications */ 830219820Sjeff 831219820Sjeff OSM_LOG_ENTER(sa->p_log); 832219820Sjeff 833219820Sjeff /* but what if the given MGID was not 0 ? */ 834219820Sjeff zero_mgid = 1; 835219820Sjeff for (i = 0; i < sizeof(p_recvd_mcmember_rec->mgid); i++) 836219820Sjeff if (p_recvd_mcmember_rec->mgid.raw[i] != 0) { 837219820Sjeff zero_mgid = 0; 838219820Sjeff break; 839219820Sjeff } 840219820Sjeff 841219820Sjeff /* 842219820Sjeff we allocate a new mlid number before we might use it 843219820Sjeff for MGID ... 844219820Sjeff */ 845219820Sjeff mlid = __get_new_mlid(sa, mcm_rec.mlid); 846219820Sjeff if (mlid == 0) { 847219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B19: " 848219820Sjeff "__get_new_mlid failed request mlid 0x%04x\n", cl_ntoh16(mcm_rec.mlid)); 849219820Sjeff status = IB_SA_MAD_STATUS_NO_RESOURCES; 850219820Sjeff goto Exit; 851219820Sjeff } 852219820Sjeff 853219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 854219820Sjeff "Obtained new mlid 0x%X\n", cl_ntoh16(mlid)); 855219820Sjeff 856219820Sjeff /* we need to create the new MGID if it was not defined */ 857219820Sjeff if (zero_mgid) { 858219820Sjeff /* create a new MGID */ 859219820Sjeff char gid_str[INET6_ADDRSTRLEN]; 860219820Sjeff 861219820Sjeff /* use the given scope state only if requested! */ 862219820Sjeff if (comp_mask & IB_MCR_COMPMASK_SCOPE) 863219820Sjeff ib_member_get_scope_state(p_recvd_mcmember_rec-> 864219820Sjeff scope_state, &scope, NULL); 865219820Sjeff else 866219820Sjeff /* to guarantee no collision with other subnets use local scope! */ 867219820Sjeff scope = IB_MC_SCOPE_LINK_LOCAL; 868219820Sjeff 869219820Sjeff p_mgid = &(mcm_rec.mgid); 870219820Sjeff p_mgid->raw[0] = 0xFF; 871219820Sjeff p_mgid->raw[1] = 0x10 | scope; 872219820Sjeff p_mgid->raw[2] = 0xA0; 873219820Sjeff p_mgid->raw[3] = 0x1B; 874219820Sjeff 875219820Sjeff /* HACK: use the SA port gid to make it globally unique */ 876219820Sjeff memcpy((&p_mgid->raw[4]), 877219820Sjeff &sa->p_subn->opt.subnet_prefix, sizeof(uint64_t)); 878219820Sjeff 879219820Sjeff /* HACK: how do we get a unique number - use the mlid twice */ 880219820Sjeff memcpy(&p_mgid->raw[10], &mlid, sizeof(uint16_t)); 881219820Sjeff memcpy(&p_mgid->raw[12], &mlid, sizeof(uint16_t)); 882219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Allocated new MGID:%s\n", 883219820Sjeff inet_ntop(AF_INET6, p_mgid->raw, gid_str, 884219820Sjeff sizeof gid_str)); 885219820Sjeff } else if (!__validate_requested_mgid(sa, &mcm_rec)) { 886219820Sjeff /* a specific MGID was requested so validate the resulting MGID */ 887219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B22: " 888219820Sjeff "Invalid requested MGID\n"); 889219820Sjeff __free_mlid(sa, mlid); 890219820Sjeff status = IB_SA_MAD_STATUS_REQ_INVALID; 891219820Sjeff goto Exit; 892219820Sjeff } 893219820Sjeff 894219820Sjeff /* check the requested parameters are realizable */ 895219820Sjeff if (__mgrp_request_is_realizable(sa, comp_mask, &mcm_rec, p_physp) == 896219820Sjeff FALSE) { 897219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B26: " 898219820Sjeff "Requested MGRP parameters are not realizable\n"); 899219820Sjeff __free_mlid(sa, mlid); 900219820Sjeff status = IB_SA_MAD_STATUS_REQ_INVALID; 901219820Sjeff goto Exit; 902219820Sjeff } 903219820Sjeff 904219820Sjeff /* create a new MC Group */ 905219820Sjeff *pp_mgrp = osm_mgrp_new(mlid); 906219820Sjeff if (*pp_mgrp == NULL) { 907219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B08: " 908219820Sjeff "osm_mgrp_new failed\n"); 909219820Sjeff __free_mlid(sa, mlid); 910219820Sjeff status = IB_SA_MAD_STATUS_NO_RESOURCES; 911219820Sjeff goto Exit; 912219820Sjeff } 913219820Sjeff 914219820Sjeff /* Initialize the mgrp */ 915219820Sjeff (*pp_mgrp)->mcmember_rec = mcm_rec; 916219820Sjeff (*pp_mgrp)->mcmember_rec.mlid = mlid; 917219820Sjeff 918219820Sjeff /* the mcmember_record should have mtu_sel, rate_sel, and pkt_lifetime_sel = 2 */ 919219820Sjeff (*pp_mgrp)->mcmember_rec.mtu &= 0x3f; 920219820Sjeff (*pp_mgrp)->mcmember_rec.mtu |= 2 << 6; /* exactly */ 921219820Sjeff (*pp_mgrp)->mcmember_rec.rate &= 0x3f; 922219820Sjeff (*pp_mgrp)->mcmember_rec.rate |= 2 << 6; /* exactly */ 923219820Sjeff (*pp_mgrp)->mcmember_rec.pkt_life &= 0x3f; 924219820Sjeff (*pp_mgrp)->mcmember_rec.pkt_life |= 2 << 6; /* exactly */ 925219820Sjeff 926219820Sjeff /* Insert the new group in the data base */ 927219820Sjeff 928219820Sjeff /* since we might have an old group by that mlid 929219820Sjeff one whose deletion was delayed for an idle time 930219820Sjeff we need to deallocate it first */ 931219820Sjeff p_prev_mgrp = osm_get_mgrp_by_mlid(sa->p_subn, mlid); 932219820Sjeff if (p_prev_mgrp) { 933219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 934219820Sjeff "Found previous group for mlid:0x%04x - " 935219820Sjeff "Destroying it first\n", 936219820Sjeff cl_ntoh16(mlid)); 937219820Sjeff sa->p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = NULL; 938219820Sjeff osm_mgrp_delete(p_prev_mgrp); 939219820Sjeff } 940219820Sjeff 941219820Sjeff sa->p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = *pp_mgrp; 942219820Sjeff 943219820SjeffExit: 944219820Sjeff OSM_LOG_EXIT(sa->p_log); 945219820Sjeff return status; 946219820Sjeff} 947219820Sjeff 948219820Sjeff/********************************************************************** 949219820Sjeff *********************************************************************/ 950219820Sjeffstatic unsigned match_mgrp_by_mgid(IN osm_mgrp_t * const p_mgrp, ib_gid_t *mgid) 951219820Sjeff{ 952219820Sjeff /* ignore groups marked for deletion */ 953219820Sjeff if (p_mgrp->to_be_deleted || 954219820Sjeff memcmp(&p_mgrp->mcmember_rec.mgid, mgid, sizeof(ib_gid_t))) 955219820Sjeff return 0; 956219820Sjeff else 957219820Sjeff return 1; 958219820Sjeff} 959219820Sjeff 960219820Sjeff/********************************************************************** 961219820Sjeff **********************************************************************/ 962219820Sjeff#define PREFIX_MASK CL_HTON64(0xff10ffff0000ffffULL) 963219820Sjeff#define PREFIX_SIGNATURE CL_HTON64(0xff10601b00000000ULL) 964219820Sjeff#define INT_ID_MASK CL_HTON64(0xfffffff1ff000000ULL) 965219820Sjeff#define INT_ID_SIGNATURE CL_HTON64(0x00000001ff000000ULL) 966219820Sjeff 967219820Sjeff/* Special Case IPv6 Solicited Node Multicast (SNM) addresses */ 968219820Sjeff/* 0xff1Z601bXXXX0000 : 0x00000001ffYYYYYY */ 969219820Sjeff/* Where Z is the scope, XXXX is the P_Key, and 970219820Sjeff * YYYYYY is the last 24 bits of the port guid */ 971219820Sjeffstatic unsigned match_and_update_ipv6_snm_mgid(ib_gid_t *mgid) 972219820Sjeff{ 973219820Sjeff if ((mgid->unicast.prefix & PREFIX_MASK) == PREFIX_SIGNATURE && 974219820Sjeff (mgid->unicast.interface_id & INT_ID_MASK) == INT_ID_SIGNATURE) { 975219820Sjeff mgid->unicast.prefix &= PREFIX_MASK; 976219820Sjeff mgid->unicast.interface_id &= INT_ID_MASK; 977219820Sjeff return 1; 978219820Sjeff } 979219820Sjeff return 0; 980219820Sjeff} 981219820Sjeff 982219820Sjeffosm_mgrp_t *osm_get_mgrp_by_mgid(IN osm_sa_t *sa, IN ib_gid_t *p_mgid) 983219820Sjeff{ 984219820Sjeff int i; 985219820Sjeff 986219820Sjeff if (sa->p_subn->opt.consolidate_ipv6_snm_req && 987219820Sjeff match_and_update_ipv6_snm_mgid(p_mgid)) { 988219820Sjeff char gid_str[INET6_ADDRSTRLEN]; 989219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 990219820Sjeff "Special Case Solicited Node Mcast Join for MGID %s\n", 991219820Sjeff inet_ntop(AF_INET6, p_mgid->raw, gid_str, 992219820Sjeff sizeof gid_str)); 993219820Sjeff } 994219820Sjeff 995219820Sjeff for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; 996219820Sjeff i++) 997219820Sjeff if (sa->p_subn->mgroups[i] && 998219820Sjeff match_mgrp_by_mgid(sa->p_subn->mgroups[i], p_mgid)) 999219820Sjeff return sa->p_subn->mgroups[i]; 1000219820Sjeff 1001219820Sjeff return NULL; 1002219820Sjeff} 1003219820Sjeff 1004219820Sjeff/********************************************************************** 1005219820Sjeff Call this function to find or create a new mgrp. 1006219820Sjeff**********************************************************************/ 1007219820Sjeffib_api_status_t 1008219820Sjeffosm_mcmr_rcv_find_or_create_new_mgrp(IN osm_sa_t * sa, 1009219820Sjeff IN ib_net64_t comp_mask, 1010219820Sjeff IN ib_member_rec_t * 1011219820Sjeff const p_recvd_mcmember_rec, 1012219820Sjeff OUT osm_mgrp_t ** pp_mgrp) 1013219820Sjeff{ 1014219820Sjeff osm_mgrp_t *mgrp; 1015219820Sjeff 1016219820Sjeff if ((mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid))) { 1017219820Sjeff *pp_mgrp = mgrp; 1018219820Sjeff return IB_SUCCESS; 1019219820Sjeff } 1020219820Sjeff return osm_mcmr_rcv_create_new_mgrp(sa, comp_mask, 1021219820Sjeff p_recvd_mcmember_rec, NULL, 1022219820Sjeff pp_mgrp); 1023219820Sjeff} 1024219820Sjeff 1025219820Sjeff/********************************************************************* 1026219820SjeffProcess a request for leaving the group 1027219820Sjeff**********************************************************************/ 1028219820Sjeffstatic void 1029219820Sjeff__osm_mcmr_rcv_leave_mgrp(IN osm_sa_t * sa, 1030219820Sjeff IN osm_madw_t * const p_madw) 1031219820Sjeff{ 1032219820Sjeff osm_mgrp_t *p_mgrp; 1033219820Sjeff ib_sa_mad_t *p_sa_mad; 1034219820Sjeff ib_member_rec_t *p_recvd_mcmember_rec; 1035219820Sjeff ib_member_rec_t mcmember_rec; 1036219820Sjeff ib_net16_t mlid; 1037219820Sjeff ib_net64_t portguid; 1038219820Sjeff osm_mcm_port_t *p_mcm_port; 1039219820Sjeff int removed; 1040219820Sjeff 1041219820Sjeff OSM_LOG_ENTER(sa->p_log); 1042219820Sjeff 1043219820Sjeff p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); 1044219820Sjeff p_recvd_mcmember_rec = 1045219820Sjeff (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); 1046219820Sjeff 1047219820Sjeff mcmember_rec = *p_recvd_mcmember_rec; 1048219820Sjeff 1049219820Sjeff if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) { 1050219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of record\n"); 1051219820Sjeff osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG); 1052219820Sjeff } 1053219820Sjeff 1054219820Sjeff CL_PLOCK_EXCL_ACQUIRE(sa->p_lock); 1055219820Sjeff p_mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid); 1056219820Sjeff if (!p_mgrp) { 1057219820Sjeff char gid_str[INET6_ADDRSTRLEN]; 1058219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1059219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 1060219820Sjeff "Failed since multicast group %s not present\n", 1061219820Sjeff inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw, 1062219820Sjeff gid_str, sizeof gid_str)); 1063219820Sjeff osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); 1064219820Sjeff goto Exit; 1065219820Sjeff } 1066219820Sjeff 1067219820Sjeff mlid = p_mgrp->mlid; 1068219820Sjeff portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; 1069219820Sjeff 1070219820Sjeff /* check validity of the delete request o15-0.1.14 */ 1071219820Sjeff if (!__validate_delete(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw), 1072219820Sjeff p_recvd_mcmember_rec, &p_mcm_port)) { 1073219820Sjeff char gid_str[INET6_ADDRSTRLEN]; 1074219820Sjeff char gid_str2[INET6_ADDRSTRLEN]; 1075219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1076219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B25: " 1077219820Sjeff "Received an invalid delete request for " 1078219820Sjeff "MGID: %s for PortGID: %s\n", 1079219820Sjeff inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw, 1080219820Sjeff gid_str, sizeof gid_str), 1081219820Sjeff inet_ntop(AF_INET6, p_recvd_mcmember_rec->port_gid.raw, 1082219820Sjeff gid_str2, sizeof gid_str2)); 1083219820Sjeff osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); 1084219820Sjeff goto Exit; 1085219820Sjeff } 1086219820Sjeff 1087219820Sjeff /* store state - we'll need it if the port is removed */ 1088219820Sjeff mcmember_rec.scope_state = p_mcm_port->scope_state; 1089219820Sjeff 1090219820Sjeff /* remove port or update join state */ 1091219820Sjeff removed = osm_mgrp_remove_port(sa->p_subn, sa->p_log, p_mgrp, p_mcm_port, 1092219820Sjeff p_recvd_mcmember_rec->scope_state&0x0F); 1093219820Sjeff if (!removed) 1094219820Sjeff mcmember_rec.scope_state = p_mcm_port->scope_state; 1095219820Sjeff 1096219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1097219820Sjeff 1098219820Sjeff /* we can leave if port was deleted from MCG */ 1099219820Sjeff if (removed && osm_sm_mcgrp_leave(sa->sm, mlid, portguid)) 1100219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B09: " 1101219820Sjeff "osm_sm_mcgrp_leave failed\n"); 1102219820Sjeff 1103219820Sjeff /* Send an SA response */ 1104219820Sjeff __osm_mcmr_rcv_respond(sa, p_madw, &mcmember_rec); 1105219820Sjeff 1106219820SjeffExit: 1107219820Sjeff OSM_LOG_EXIT(sa->p_log); 1108219820Sjeff} 1109219820Sjeff 1110219820Sjeff/********************************************************************** 1111219820Sjeff Handle a join (or create) request 1112219820Sjeff**********************************************************************/ 1113219820Sjeffstatic void 1114219820Sjeff__osm_mcmr_rcv_join_mgrp(IN osm_sa_t * sa, IN osm_madw_t * const p_madw) 1115219820Sjeff{ 1116219820Sjeff osm_mgrp_t *p_mgrp = NULL; 1117219820Sjeff ib_api_status_t status; 1118219820Sjeff ib_sa_mad_t *p_sa_mad; 1119219820Sjeff ib_member_rec_t *p_recvd_mcmember_rec; 1120219820Sjeff ib_member_rec_t mcmember_rec; 1121219820Sjeff ib_net16_t mlid; 1122219820Sjeff osm_mcm_port_t *p_mcmr_port; 1123219820Sjeff ib_net64_t portguid; 1124219820Sjeff osm_port_t *p_port; 1125219820Sjeff osm_physp_t *p_physp; 1126219820Sjeff osm_physp_t *p_request_physp; 1127219820Sjeff uint8_t is_new_group; /* TRUE = there is a need to create a group */ 1128219820Sjeff osm_mcast_req_type_t req_type; 1129219820Sjeff uint8_t join_state; 1130219820Sjeff 1131219820Sjeff OSM_LOG_ENTER(sa->p_log); 1132219820Sjeff 1133219820Sjeff p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); 1134219820Sjeff p_recvd_mcmember_rec = ib_sa_mad_get_payload_ptr(p_sa_mad); 1135219820Sjeff 1136219820Sjeff portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; 1137219820Sjeff 1138219820Sjeff mcmember_rec = *p_recvd_mcmember_rec; 1139219820Sjeff 1140219820Sjeff if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) { 1141219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of incoming record\n"); 1142219820Sjeff osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG); 1143219820Sjeff } 1144219820Sjeff 1145219820Sjeff CL_PLOCK_EXCL_ACQUIRE(sa->p_lock); 1146219820Sjeff 1147219820Sjeff /* make sure the requested port guid is known to the SM */ 1148219820Sjeff p_port = osm_get_port_by_guid(sa->p_subn, portguid); 1149219820Sjeff if (!p_port) { 1150219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1151219820Sjeff 1152219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 1153219820Sjeff "Unknown port GUID 0x%016" PRIx64 "\n", 1154219820Sjeff cl_ntoh64(portguid)); 1155219820Sjeff osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); 1156219820Sjeff goto Exit; 1157219820Sjeff } 1158219820Sjeff 1159219820Sjeff p_physp = p_port->p_physp; 1160219820Sjeff /* Check that the p_physp and the requester physp are in the same 1161219820Sjeff partition. */ 1162219820Sjeff p_request_physp = 1163219820Sjeff osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, 1164219820Sjeff osm_madw_get_mad_addr_ptr(p_madw)); 1165219820Sjeff if (p_request_physp == NULL) { 1166219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1167219820Sjeff goto Exit; 1168219820Sjeff } 1169219820Sjeff 1170219820Sjeff if (!osm_physp_share_pkey(sa->p_log, p_physp, p_request_physp)) { 1171219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1172219820Sjeff 1173219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 1174219820Sjeff "Port and requester don't share pkey\n"); 1175219820Sjeff osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); 1176219820Sjeff goto Exit; 1177219820Sjeff } 1178219820Sjeff 1179219820Sjeff ib_member_get_scope_state(p_recvd_mcmember_rec->scope_state, NULL, 1180219820Sjeff &join_state); 1181219820Sjeff 1182219820Sjeff /* do we need to create a new group? */ 1183219820Sjeff p_mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid); 1184219820Sjeff if (!p_mgrp || p_mgrp->to_be_deleted) { 1185219820Sjeff /* check for JoinState.FullMember = 1 o15.0.1.9 */ 1186219820Sjeff if ((join_state & 0x01) != 0x01) { 1187219820Sjeff char gid_str[INET6_ADDRSTRLEN]; 1188219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1189219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B10: " 1190219820Sjeff "Provided Join State != FullMember - " 1191219820Sjeff "required for create, " 1192219820Sjeff "MGID: %s from port 0x%016" PRIx64 " (%s)\n", 1193219820Sjeff inet_ntop(AF_INET6, 1194219820Sjeff p_recvd_mcmember_rec->mgid.raw, 1195219820Sjeff gid_str, sizeof gid_str), 1196219820Sjeff cl_ntoh64(portguid), 1197219820Sjeff p_port->p_node->print_desc); 1198219820Sjeff osm_sa_send_error(sa, p_madw, 1199219820Sjeff IB_SA_MAD_STATUS_REQ_INVALID); 1200219820Sjeff goto Exit; 1201219820Sjeff } 1202219820Sjeff 1203219820Sjeff /* check the comp_mask */ 1204219820Sjeff if (!__check_create_comp_mask(p_sa_mad->comp_mask, 1205219820Sjeff p_recvd_mcmember_rec)) { 1206219820Sjeff char gid_str[INET6_ADDRSTRLEN]; 1207219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1208219820Sjeff 1209219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B11: " 1210219820Sjeff "method = %s, scope_state = 0x%x, " 1211219820Sjeff "component mask = 0x%016" PRIx64 ", " 1212219820Sjeff "expected comp mask = 0x%016" PRIx64 ", " 1213219820Sjeff "MGID: %s from port 0x%016" PRIx64 " (%s)\n", 1214219820Sjeff ib_get_sa_method_str(p_sa_mad->method), 1215219820Sjeff p_recvd_mcmember_rec->scope_state, 1216219820Sjeff cl_ntoh64(p_sa_mad->comp_mask), 1217219820Sjeff CL_NTOH64(REQUIRED_MC_CREATE_COMP_MASK), 1218219820Sjeff inet_ntop(AF_INET6, 1219219820Sjeff p_recvd_mcmember_rec->mgid.raw, 1220219820Sjeff gid_str, sizeof gid_str), 1221219820Sjeff cl_ntoh64(portguid), 1222219820Sjeff p_port->p_node->print_desc); 1223219820Sjeff 1224219820Sjeff osm_sa_send_error(sa, p_madw, 1225219820Sjeff IB_SA_MAD_STATUS_INSUF_COMPS); 1226219820Sjeff goto Exit; 1227219820Sjeff } 1228219820Sjeff 1229219820Sjeff status = osm_mcmr_rcv_create_new_mgrp(sa, p_sa_mad->comp_mask, 1230219820Sjeff p_recvd_mcmember_rec, 1231219820Sjeff p_physp, &p_mgrp); 1232219820Sjeff if (status != IB_SUCCESS) { 1233219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1234219820Sjeff osm_sa_send_error(sa, p_madw, status); 1235219820Sjeff goto Exit; 1236219820Sjeff } 1237219820Sjeff /* copy the MGID to the result */ 1238219820Sjeff mcmember_rec.mgid = p_mgrp->mcmember_rec.mgid; 1239219820Sjeff is_new_group = 1; 1240219820Sjeff req_type = OSM_MCAST_REQ_TYPE_CREATE; 1241219820Sjeff } else { 1242219820Sjeff /* no need for a new group */ 1243219820Sjeff is_new_group = 0; 1244219820Sjeff req_type = OSM_MCAST_REQ_TYPE_JOIN; 1245219820Sjeff } 1246219820Sjeff 1247219820Sjeff CL_ASSERT(p_mgrp); 1248219820Sjeff mlid = p_mgrp->mlid; 1249219820Sjeff 1250219820Sjeff /* 1251219820Sjeff * o15-0.2.4: If SA supports UD multicast, then SA shall cause an 1252219820Sjeff * endport to join an existing multicast group if: 1253219820Sjeff * 1. It receives a SubnAdmSet() method for a MCMemberRecord, and 1254219820Sjeff * - WE KNOW THAT ALREADY 1255219820Sjeff * 2. The MGID is specified and matches an existing multicast 1256219820Sjeff * group, and 1257219820Sjeff * - WE KNOW THAT ALREADY 1258219820Sjeff * 3. The MCMemberRecord:JoinState is not all 0s, and 1259219820Sjeff * 4. PortGID is specified and 1260219820Sjeff * - WE KNOW THAT ALREADY (as it matched a real one) 1261219820Sjeff * 5. All other components match that existing group, either by 1262219820Sjeff * being wildcarded or by having values identical to those specified 1263219820Sjeff * by the component mask and in use by the group with the exception 1264219820Sjeff * of components such as ProxyJoin and Reserved, which are ignored 1265219820Sjeff * by SA. 1266219820Sjeff * 1267219820Sjeff * We need to check #3 and #5 here: 1268219820Sjeff */ 1269219820Sjeff if (!__validate_more_comp_fields(sa->p_log, p_mgrp, 1270219820Sjeff p_recvd_mcmember_rec, 1271219820Sjeff p_sa_mad->comp_mask) 1272219820Sjeff || !__validate_port_caps(sa->p_log, p_mgrp, p_physp) 1273219820Sjeff || !(join_state != 0)) { 1274219820Sjeff /* since we might have created the new group we need to cleanup */ 1275219820Sjeff __cleanup_mgrp(sa, p_mgrp); 1276219820Sjeff 1277219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1278219820Sjeff 1279219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B12: " 1280219820Sjeff "__validate_more_comp_fields, __validate_port_caps, " 1281219820Sjeff "or JoinState = 0 failed from port 0x%016" PRIx64 1282219820Sjeff " (%s), " "sending IB_SA_MAD_STATUS_REQ_INVALID\n", 1283219820Sjeff cl_ntoh64(portguid), p_port->p_node->print_desc); 1284219820Sjeff 1285219820Sjeff osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); 1286219820Sjeff goto Exit; 1287219820Sjeff } 1288219820Sjeff 1289219820Sjeff /* 1290219820Sjeff * o15-0.2.1 requires validation of the requesting port 1291219820Sjeff * in the case of modification: 1292219820Sjeff */ 1293219820Sjeff if (!is_new_group && 1294219820Sjeff !__validate_modify(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw), 1295219820Sjeff p_recvd_mcmember_rec, &p_mcmr_port)) { 1296219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1297219820Sjeff 1298219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B13: " 1299219820Sjeff "__validate_modify failed from port 0x%016" PRIx64 1300219820Sjeff " (%s), sending IB_SA_MAD_STATUS_REQ_INVALID\n", 1301219820Sjeff cl_ntoh64(portguid), p_port->p_node->print_desc); 1302219820Sjeff 1303219820Sjeff osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); 1304219820Sjeff goto Exit; 1305219820Sjeff } 1306219820Sjeff 1307219820Sjeff /* create or update existing port (join-state will be updated) */ 1308219820Sjeff status = __add_new_mgrp_port(sa, p_mgrp, p_recvd_mcmember_rec, 1309219820Sjeff osm_madw_get_mad_addr_ptr(p_madw), 1310219820Sjeff &p_mcmr_port); 1311219820Sjeff 1312219820Sjeff if (status != IB_SUCCESS) { 1313219820Sjeff /* we fail to add the port so we might need to delete the group */ 1314219820Sjeff __cleanup_mgrp(sa, p_mgrp); 1315219820Sjeff 1316219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1317219820Sjeff 1318219820Sjeff osm_sa_send_error(sa, p_madw, status == IB_INVALID_PARAMETER ? 1319219820Sjeff IB_SA_MAD_STATUS_REQ_INVALID : 1320219820Sjeff IB_SA_MAD_STATUS_NO_RESOURCES); 1321219820Sjeff goto Exit; 1322219820Sjeff } 1323219820Sjeff 1324219820Sjeff /* o15.0.1.11: copy the join state */ 1325219820Sjeff mcmember_rec.scope_state = p_mcmr_port->scope_state; 1326219820Sjeff 1327219820Sjeff /* copy qkey mlid tclass pkey sl_flow_hop mtu rate pkt_life sl_flow_hop */ 1328219820Sjeff __copy_from_create_mc_rec(&mcmember_rec, &p_mgrp->mcmember_rec); 1329219820Sjeff 1330219820Sjeff /* Release the lock as we don't need it. */ 1331219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1332219820Sjeff 1333219820Sjeff /* do the actual routing (actually schedule the update) */ 1334219820Sjeff status = osm_sm_mcgrp_join(sa->sm, mlid, 1335219820Sjeff p_recvd_mcmember_rec->port_gid.unicast. 1336219820Sjeff interface_id, req_type); 1337219820Sjeff 1338219820Sjeff if (status != IB_SUCCESS) { 1339219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B14: " 1340219820Sjeff "osm_sm_mcgrp_join failed from port 0x%016" PRIx64 1341219820Sjeff " (%s), " "sending IB_SA_MAD_STATUS_NO_RESOURCES\n", 1342219820Sjeff cl_ntoh64(portguid), p_port->p_node->print_desc); 1343219820Sjeff 1344219820Sjeff CL_PLOCK_EXCL_ACQUIRE(sa->p_lock); 1345219820Sjeff 1346219820Sjeff /* the request for routing failed so we need to remove the port */ 1347219820Sjeff osm_mgrp_delete_port(sa->p_subn, sa->p_log, p_mgrp, 1348219820Sjeff p_recvd_mcmember_rec->port_gid. 1349219820Sjeff unicast.interface_id); 1350219820Sjeff __cleanup_mgrp(sa, p_mgrp); 1351219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1352219820Sjeff osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES); 1353219820Sjeff goto Exit; 1354219820Sjeff 1355219820Sjeff } 1356219820Sjeff /* failed to route */ 1357219820Sjeff if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) 1358219820Sjeff osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG); 1359219820Sjeff 1360219820Sjeff __osm_mcmr_rcv_respond(sa, p_madw, &mcmember_rec); 1361219820Sjeff 1362219820SjeffExit: 1363219820Sjeff OSM_LOG_EXIT(sa->p_log); 1364219820Sjeff} 1365219820Sjeff 1366219820Sjeff/********************************************************************** 1367219820Sjeff Add a patched multicast group to the results list 1368219820Sjeff**********************************************************************/ 1369219820Sjeffstatic ib_api_status_t 1370219820Sjeff__osm_mcmr_rcv_new_mcmr(IN osm_sa_t * sa, 1371219820Sjeff IN const ib_member_rec_t * p_rcvd_rec, 1372219820Sjeff IN cl_qlist_t * const p_list) 1373219820Sjeff{ 1374219820Sjeff osm_mcmr_item_t *p_rec_item; 1375219820Sjeff ib_api_status_t status = IB_SUCCESS; 1376219820Sjeff 1377219820Sjeff OSM_LOG_ENTER(sa->p_log); 1378219820Sjeff 1379219820Sjeff p_rec_item = malloc(sizeof(*p_rec_item)); 1380219820Sjeff if (p_rec_item == NULL) { 1381219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B15: " 1382219820Sjeff "rec_item alloc failed\n"); 1383219820Sjeff status = IB_INSUFFICIENT_RESOURCES; 1384219820Sjeff goto Exit; 1385219820Sjeff } 1386219820Sjeff 1387219820Sjeff memset(p_rec_item, 0, sizeof(*p_rec_item)); 1388219820Sjeff 1389219820Sjeff /* HACK: Untrusted requesters should result with 0 Join 1390219820Sjeff State, Port Guid, and Proxy */ 1391219820Sjeff p_rec_item->rec = *p_rcvd_rec; 1392219820Sjeff cl_qlist_insert_tail(p_list, &p_rec_item->list_item); 1393219820Sjeff 1394219820SjeffExit: 1395219820Sjeff OSM_LOG_EXIT(sa->p_log); 1396219820Sjeff return (status); 1397219820Sjeff} 1398219820Sjeff 1399219820Sjeff/********************************************************************** 1400219820Sjeff Match the given mgrp to the requested mcmr 1401219820Sjeff**********************************************************************/ 1402219820Sjeffstatic void mcmr_by_comp_mask(osm_sa_t *sa, const ib_member_rec_t *p_rcvd_rec, 1403219820Sjeff ib_net64_t comp_mask, osm_mgrp_t *p_mgrp, 1404219820Sjeff const osm_physp_t *p_req_physp, 1405219820Sjeff boolean_t trusted_req, cl_qlist_t *list) 1406219820Sjeff{ 1407219820Sjeff /* since we might change scope_state */ 1408219820Sjeff ib_member_rec_t match_rec; 1409219820Sjeff osm_mcm_port_t *p_mcm_port; 1410219820Sjeff ib_net64_t portguid = p_rcvd_rec->port_gid.unicast.interface_id; 1411219820Sjeff /* will be used for group or port info */ 1412219820Sjeff uint8_t scope_state; 1413219820Sjeff uint8_t scope_state_mask = 0; 1414219820Sjeff cl_map_item_t *p_item; 1415219820Sjeff ib_gid_t port_gid; 1416219820Sjeff boolean_t proxy_join = FALSE; 1417219820Sjeff 1418219820Sjeff OSM_LOG_ENTER(sa->p_log); 1419219820Sjeff 1420219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 1421219820Sjeff "Checking mlid:0x%X\n", cl_ntoh16(p_mgrp->mlid)); 1422219820Sjeff 1423219820Sjeff /* the group might be marked for deletion */ 1424219820Sjeff if (p_mgrp->to_be_deleted) { 1425219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 1426219820Sjeff "Group mlid:0x%X is marked to be deleted\n", 1427219820Sjeff cl_ntoh16(p_mgrp->mlid)); 1428219820Sjeff goto Exit; 1429219820Sjeff } 1430219820Sjeff 1431219820Sjeff /* first try to eliminate the group by MGID, MLID, or P_Key */ 1432219820Sjeff if ((IB_MCR_COMPMASK_MGID & comp_mask) && 1433219820Sjeff memcmp(&p_rcvd_rec->mgid, &p_mgrp->mcmember_rec.mgid, 1434219820Sjeff sizeof(ib_gid_t))) 1435219820Sjeff goto Exit; 1436219820Sjeff 1437219820Sjeff if ((IB_MCR_COMPMASK_MLID & comp_mask) && 1438219820Sjeff memcmp(&p_rcvd_rec->mlid, &p_mgrp->mcmember_rec.mlid, 1439219820Sjeff sizeof(uint16_t))) 1440219820Sjeff goto Exit; 1441219820Sjeff 1442219820Sjeff /* if the requester physical port doesn't have the pkey that is defined 1443219820Sjeff for the group - exit. */ 1444219820Sjeff if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey, 1445219820Sjeff p_req_physp)) 1446219820Sjeff goto Exit; 1447219820Sjeff 1448219820Sjeff /* now do the rest of the match */ 1449219820Sjeff if ((IB_MCR_COMPMASK_QKEY & comp_mask) && 1450219820Sjeff p_rcvd_rec->qkey != p_mgrp->mcmember_rec.qkey) 1451219820Sjeff goto Exit; 1452219820Sjeff 1453219820Sjeff if ((IB_MCR_COMPMASK_PKEY & comp_mask) && 1454219820Sjeff p_rcvd_rec->pkey != p_mgrp->mcmember_rec.pkey) 1455219820Sjeff goto Exit; 1456219820Sjeff 1457219820Sjeff if ((IB_MCR_COMPMASK_TCLASS & comp_mask) && 1458219820Sjeff p_rcvd_rec->tclass != p_mgrp->mcmember_rec.tclass) 1459219820Sjeff goto Exit; 1460219820Sjeff 1461219820Sjeff /* check SL, Flow, and Hop limit */ 1462219820Sjeff { 1463219820Sjeff uint8_t mgrp_sl, query_sl; 1464219820Sjeff uint32_t mgrp_flow, query_flow; 1465219820Sjeff uint8_t mgrp_hop, query_hop; 1466219820Sjeff 1467219820Sjeff ib_member_get_sl_flow_hop(p_rcvd_rec->sl_flow_hop, 1468219820Sjeff &query_sl, &query_flow, &query_hop); 1469219820Sjeff 1470219820Sjeff ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop, 1471219820Sjeff &mgrp_sl, &mgrp_flow, &mgrp_hop); 1472219820Sjeff 1473219820Sjeff if ((IB_MCR_COMPMASK_SL & comp_mask) && query_sl != mgrp_sl) 1474219820Sjeff goto Exit; 1475219820Sjeff 1476219820Sjeff if ((IB_MCR_COMPMASK_FLOW & comp_mask) && 1477219820Sjeff query_flow != mgrp_flow) 1478219820Sjeff goto Exit; 1479219820Sjeff 1480219820Sjeff if ((IB_MCR_COMPMASK_HOP & comp_mask) && query_hop != mgrp_hop) 1481219820Sjeff goto Exit; 1482219820Sjeff } 1483219820Sjeff 1484219820Sjeff if ((IB_MCR_COMPMASK_PROXY & comp_mask) && 1485219820Sjeff p_rcvd_rec->proxy_join != p_mgrp->mcmember_rec.proxy_join) 1486219820Sjeff goto Exit; 1487219820Sjeff 1488219820Sjeff /* need to validate mtu, rate, and pkt_lifetime fields */ 1489219820Sjeff if (__validate_more_comp_fields(sa->p_log, p_mgrp, p_rcvd_rec, 1490219820Sjeff comp_mask) == FALSE) 1491219820Sjeff goto Exit; 1492219820Sjeff 1493219820Sjeff /* Port specific fields */ 1494219820Sjeff /* so did we get the PortGUID mask */ 1495219820Sjeff if (IB_MCR_COMPMASK_PORT_GID & comp_mask) { 1496219820Sjeff /* try to find this port */ 1497219820Sjeff if (osm_mgrp_is_port_present(p_mgrp, portguid, &p_mcm_port)) { 1498219820Sjeff scope_state = p_mcm_port->scope_state; 1499219820Sjeff memcpy(&port_gid, &(p_mcm_port->port_gid), 1500219820Sjeff sizeof(ib_gid_t)); 1501219820Sjeff proxy_join = p_mcm_port->proxy_join; 1502219820Sjeff } else { 1503219820Sjeff /* port not in group */ 1504219820Sjeff goto Exit; 1505219820Sjeff } 1506219820Sjeff } else { 1507219820Sjeff /* point to the group information */ 1508219820Sjeff scope_state = p_mgrp->mcmember_rec.scope_state; 1509219820Sjeff } 1510219820Sjeff 1511219820Sjeff if (IB_MCR_COMPMASK_SCOPE & comp_mask) 1512219820Sjeff scope_state_mask = 0xF0; 1513219820Sjeff 1514219820Sjeff if (IB_MCR_COMPMASK_JOIN_STATE & comp_mask) 1515219820Sjeff scope_state_mask = scope_state_mask | 0x0F; 1516219820Sjeff 1517219820Sjeff /* Many MC records returned */ 1518219820Sjeff if (trusted_req == TRUE 1519219820Sjeff && !(IB_MCR_COMPMASK_PORT_GID & comp_mask)) { 1520219820Sjeff char gid_str[INET6_ADDRSTRLEN]; 1521219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 1522219820Sjeff "Trusted req is TRUE and no specific port defined\n"); 1523219820Sjeff 1524219820Sjeff /* return all the ports that match in this MC group */ 1525219820Sjeff p_item = cl_qmap_head(&(p_mgrp->mcm_port_tbl)); 1526219820Sjeff while (p_item != cl_qmap_end(&(p_mgrp->mcm_port_tbl))) { 1527219820Sjeff p_mcm_port = (osm_mcm_port_t *) p_item; 1528219820Sjeff 1529219820Sjeff if ((scope_state_mask & p_rcvd_rec->scope_state) == 1530219820Sjeff (scope_state_mask & p_mcm_port->scope_state)) { 1531219820Sjeff /* add to the list */ 1532219820Sjeff match_rec = p_mgrp->mcmember_rec; 1533219820Sjeff match_rec.scope_state = p_mcm_port->scope_state; 1534219820Sjeff memcpy(&(match_rec.port_gid), 1535219820Sjeff &(p_mcm_port->port_gid), 1536219820Sjeff sizeof(ib_gid_t)); 1537219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 1538219820Sjeff "Record of port_gid: %s" 1539219820Sjeff " in multicast_lid: 0x%X is returned\n", 1540219820Sjeff inet_ntop(AF_INET6, match_rec.port_gid.raw, 1541219820Sjeff gid_str, sizeof gid_str), 1542219820Sjeff cl_ntoh16(p_mgrp->mlid)); 1543219820Sjeff 1544219820Sjeff match_rec.proxy_join = 1545219820Sjeff (uint8_t) (p_mcm_port->proxy_join); 1546219820Sjeff 1547219820Sjeff __osm_mcmr_rcv_new_mcmr(sa, &match_rec, list); 1548219820Sjeff } 1549219820Sjeff p_item = cl_qmap_next(p_item); 1550219820Sjeff } 1551219820Sjeff } 1552219820Sjeff /* One MC record returned */ 1553219820Sjeff else { 1554219820Sjeff if ((scope_state_mask & p_rcvd_rec->scope_state) != 1555219820Sjeff (scope_state_mask & scope_state)) 1556219820Sjeff goto Exit; 1557219820Sjeff 1558219820Sjeff /* add to the list */ 1559219820Sjeff match_rec = p_mgrp->mcmember_rec; 1560219820Sjeff match_rec.scope_state = scope_state; 1561219820Sjeff memcpy(&(match_rec.port_gid), &port_gid, sizeof(ib_gid_t)); 1562219820Sjeff match_rec.proxy_join = (uint8_t) proxy_join; 1563219820Sjeff 1564219820Sjeff __osm_mcmr_rcv_new_mcmr(sa, &match_rec, list); 1565219820Sjeff } 1566219820Sjeff 1567219820SjeffExit: 1568219820Sjeff OSM_LOG_EXIT(sa->p_log); 1569219820Sjeff} 1570219820Sjeff 1571219820Sjeff/********************************************************************** 1572219820Sjeff Handle a query request 1573219820Sjeff**********************************************************************/ 1574219820Sjeffstatic void 1575219820Sjeff__osm_mcmr_query_mgrp(IN osm_sa_t * sa, 1576219820Sjeff IN osm_madw_t * const p_madw) 1577219820Sjeff{ 1578219820Sjeff const ib_sa_mad_t *p_rcvd_mad; 1579219820Sjeff const ib_member_rec_t *p_rcvd_rec; 1580219820Sjeff cl_qlist_t rec_list; 1581219820Sjeff ib_net64_t comp_mask; 1582219820Sjeff osm_physp_t *p_req_physp; 1583219820Sjeff boolean_t trusted_req; 1584219820Sjeff osm_mgrp_t *p_mgrp; 1585219820Sjeff int i; 1586219820Sjeff 1587219820Sjeff OSM_LOG_ENTER(sa->p_log); 1588219820Sjeff 1589219820Sjeff p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); 1590219820Sjeff p_rcvd_rec = (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); 1591219820Sjeff comp_mask = p_rcvd_mad->comp_mask; 1592219820Sjeff 1593219820Sjeff /* 1594219820Sjeff if sm_key is not zero and does not match we never get here 1595219820Sjeff see main SA receiver 1596219820Sjeff */ 1597219820Sjeff trusted_req = (p_rcvd_mad->sm_key != 0); 1598219820Sjeff 1599219820Sjeff /* update the requester physical port. */ 1600219820Sjeff p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, 1601219820Sjeff osm_madw_get_mad_addr_ptr 1602219820Sjeff (p_madw)); 1603219820Sjeff if (p_req_physp == NULL) { 1604219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B04: " 1605219820Sjeff "Cannot find requester physical port\n"); 1606219820Sjeff goto Exit; 1607219820Sjeff } 1608219820Sjeff 1609219820Sjeff cl_qlist_init(&rec_list); 1610219820Sjeff 1611219820Sjeff CL_PLOCK_ACQUIRE(sa->p_lock); 1612219820Sjeff 1613219820Sjeff /* simply go over all MCGs and match */ 1614219820Sjeff for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; 1615219820Sjeff i++) { 1616219820Sjeff p_mgrp = sa->p_subn->mgroups[i]; 1617219820Sjeff if (p_mgrp) 1618219820Sjeff mcmr_by_comp_mask(sa, p_rcvd_rec, comp_mask, p_mgrp, 1619219820Sjeff p_req_physp, trusted_req, &rec_list); 1620219820Sjeff } 1621219820Sjeff 1622219820Sjeff CL_PLOCK_RELEASE(sa->p_lock); 1623219820Sjeff 1624219820Sjeff /* 1625219820Sjeff p923 - The PortGID, JoinState and ProxyJoin shall be zero, 1626219820Sjeff except in the case of a trusted request. 1627219820Sjeff Note: In the mad controller we check that the SM_Key received on 1628219820Sjeff the mad is valid. Meaning - is either zero or equal to the local 1629219820Sjeff sm_key. 1630219820Sjeff */ 1631219820Sjeff 1632219820Sjeff if (!p_rcvd_mad->sm_key) { 1633219820Sjeff osm_mcmr_item_t *item; 1634219820Sjeff for (item = (osm_mcmr_item_t *) cl_qlist_head(&rec_list); 1635219820Sjeff item != (osm_mcmr_item_t *) cl_qlist_end(&rec_list); 1636219820Sjeff item = (osm_mcmr_item_t *)cl_qlist_next(&item->list_item)) { 1637219820Sjeff memset(&item->rec.port_gid, 0, sizeof(ib_gid_t)); 1638219820Sjeff ib_member_set_join_state(&item->rec, 0); 1639219820Sjeff item->rec.proxy_join = 0; 1640219820Sjeff } 1641219820Sjeff } 1642219820Sjeff 1643219820Sjeff osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list); 1644219820Sjeff 1645219820SjeffExit: 1646219820Sjeff OSM_LOG_EXIT(sa->p_log); 1647219820Sjeff} 1648219820Sjeff 1649219820Sjeff/********************************************************************** 1650219820Sjeff **********************************************************************/ 1651219820Sjeffvoid osm_mcmr_rcv_process(IN void *context, IN void *data) 1652219820Sjeff{ 1653219820Sjeff osm_sa_t *sa = context; 1654219820Sjeff osm_madw_t *p_madw = data; 1655219820Sjeff ib_sa_mad_t *p_sa_mad; 1656219820Sjeff ib_member_rec_t *p_recvd_mcmember_rec; 1657219820Sjeff 1658219820Sjeff CL_ASSERT(sa); 1659219820Sjeff 1660219820Sjeff OSM_LOG_ENTER(sa->p_log); 1661219820Sjeff 1662219820Sjeff CL_ASSERT(p_madw); 1663219820Sjeff 1664219820Sjeff p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); 1665219820Sjeff p_recvd_mcmember_rec = 1666219820Sjeff (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); 1667219820Sjeff 1668219820Sjeff CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MCMEMBER_RECORD); 1669219820Sjeff 1670219820Sjeff switch (p_sa_mad->method) { 1671219820Sjeff case IB_MAD_METHOD_SET: 1672219820Sjeff if (!__check_join_comp_mask(p_sa_mad->comp_mask)) { 1673219820Sjeff char gid_str[INET6_ADDRSTRLEN]; 1674219820Sjeff char gid_str2[INET6_ADDRSTRLEN]; 1675219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B18: " 1676219820Sjeff "component mask = 0x%016" PRIx64 ", " 1677219820Sjeff "expected comp mask = 0x%016" PRIx64 ", " 1678219820Sjeff "MGID: %s for PortGID: %s\n", 1679219820Sjeff cl_ntoh64(p_sa_mad->comp_mask), 1680219820Sjeff CL_NTOH64(JOIN_MC_COMP_MASK), 1681219820Sjeff inet_ntop(AF_INET6, 1682219820Sjeff p_recvd_mcmember_rec->mgid.raw, 1683219820Sjeff gid_str, sizeof gid_str), 1684219820Sjeff inet_ntop(AF_INET6, 1685219820Sjeff p_recvd_mcmember_rec->port_gid.raw, 1686219820Sjeff gid_str2, sizeof gid_str2)); 1687219820Sjeff 1688219820Sjeff osm_sa_send_error(sa, p_madw, 1689219820Sjeff IB_SA_MAD_STATUS_REQ_INVALID); 1690219820Sjeff goto Exit; 1691219820Sjeff } 1692219820Sjeff 1693219820Sjeff /* 1694219820Sjeff * Join or Create Multicast Group 1695219820Sjeff */ 1696219820Sjeff __osm_mcmr_rcv_join_mgrp(sa, p_madw); 1697219820Sjeff break; 1698219820Sjeff case IB_MAD_METHOD_DELETE: 1699219820Sjeff if (!__check_join_comp_mask(p_sa_mad->comp_mask)) { 1700219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B20: " 1701219820Sjeff "component mask = 0x%016" PRIx64 ", " 1702219820Sjeff "expected comp mask = 0x%016" PRIx64 "\n", 1703219820Sjeff cl_ntoh64(p_sa_mad->comp_mask), 1704219820Sjeff CL_NTOH64(JOIN_MC_COMP_MASK)); 1705219820Sjeff 1706219820Sjeff osm_sa_send_error(sa, p_madw, 1707219820Sjeff IB_SA_MAD_STATUS_REQ_INVALID); 1708219820Sjeff goto Exit; 1709219820Sjeff } 1710219820Sjeff 1711219820Sjeff /* 1712219820Sjeff * Leave Multicast Group 1713219820Sjeff */ 1714219820Sjeff __osm_mcmr_rcv_leave_mgrp(sa, p_madw); 1715219820Sjeff break; 1716219820Sjeff case IB_MAD_METHOD_GET: 1717219820Sjeff case IB_MAD_METHOD_GETTABLE: 1718219820Sjeff /* 1719219820Sjeff * Querying a Multicast Group 1720219820Sjeff */ 1721219820Sjeff __osm_mcmr_query_mgrp(sa, p_madw); 1722219820Sjeff break; 1723219820Sjeff default: 1724219820Sjeff OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B21: " 1725219820Sjeff "Unsupported Method (%s)\n", 1726219820Sjeff ib_get_sa_method_str(p_sa_mad->method)); 1727219820Sjeff osm_sa_send_error(sa, p_madw, 1728219820Sjeff IB_MAD_STATUS_UNSUP_METHOD_ATTR); 1729219820Sjeff break; 1730219820Sjeff } 1731219820Sjeff 1732219820SjeffExit: 1733219820Sjeff OSM_LOG_EXIT(sa->p_log); 1734219820Sjeff return; 1735219820Sjeff} 1736