Blame opensm/osm_multicast.c

Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * This software is available to you under a choice of one of two
Packit Service 54dbc3
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit Service 54dbc3
 * General Public License (GPL) Version 2, available from the file
Packit Service 54dbc3
 * COPYING in the main directory of this source tree, or the
Packit Service 54dbc3
 * OpenIB.org BSD license below:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *     Redistribution and use in source and binary forms, with or
Packit Service 54dbc3
 *     without modification, are permitted provided that the following
Packit Service 54dbc3
 *     conditions are met:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions of source code must retain the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions in binary form must reproduce the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer in the documentation and/or other materials
Packit Service 54dbc3
 *        provided with the distribution.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service 54dbc3
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service 54dbc3
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service 54dbc3
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service 54dbc3
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service 54dbc3
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service 54dbc3
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service 54dbc3
 * SOFTWARE.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Abstract:
Packit Service 54dbc3
 *    Implementation of multicast functions.
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
#if HAVE_CONFIG_H
Packit Service 54dbc3
#  include <config.h>
Packit Service 54dbc3
#endif				/* HAVE_CONFIG_H */
Packit Service 54dbc3
Packit Service 54dbc3
#include <stdlib.h>
Packit Service 54dbc3
#include <string.h>
Packit Service 54dbc3
#include <arpa/inet.h>
Packit Service 54dbc3
#include <opensm/osm_file_ids.h>
Packit Service 54dbc3
#define FILE_ID OSM_FILE_MULTICAST_C
Packit Service 54dbc3
#include <opensm/osm_multicast.h>
Packit Service 54dbc3
#include <opensm/osm_mcm_port.h>
Packit Service 54dbc3
#include <opensm/osm_mtree.h>
Packit Service 54dbc3
#include <opensm/osm_inform.h>
Packit Service 54dbc3
#include <opensm/osm_opensm.h>
Packit Service 54dbc3
Packit Service 54dbc3
static osm_mgrp_box_t *mgrp_box_new(uint16_t mlid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mgrp_box_t *mbox = malloc(sizeof(*mbox));
Packit Service 54dbc3
	if (!mbox)
Packit Service 54dbc3
		return NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	memset(mbox, 0, sizeof(*mbox));
Packit Service 54dbc3
	mbox->mlid = mlid;
Packit Service 54dbc3
	cl_qlist_init(&mbox->mgrp_list);
Packit Service 54dbc3
Packit Service 54dbc3
	return mbox;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void mgrp_box_delete(osm_mgrp_box_t *mbox)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mtree_destroy(mbox->root);
Packit Service 54dbc3
	free(mbox);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void mgrp_delete(IN osm_mgrp_t * p_mgrp)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mcm_alias_guid_t *p_mcm_alias_guid, *p_next_mcm_alias_guid;
Packit Service 54dbc3
	osm_mcm_port_t *p_mcm_port, *p_next_mcm_port;
Packit Service 54dbc3
Packit Service 54dbc3
	CL_ASSERT(p_mgrp);
Packit Service 54dbc3
Packit Service 54dbc3
	p_next_mcm_alias_guid =
Packit Service 54dbc3
	    (osm_mcm_alias_guid_t *) cl_qmap_head(&p_mgrp->mcm_alias_port_tbl);
Packit Service 54dbc3
	while (p_next_mcm_alias_guid !=
Packit Service 54dbc3
	       (osm_mcm_alias_guid_t *) cl_qmap_end(&p_mgrp->mcm_alias_port_tbl)) {
Packit Service 54dbc3
		p_mcm_alias_guid = p_next_mcm_alias_guid;
Packit Service 54dbc3
		p_next_mcm_alias_guid =
Packit Service 54dbc3
		    (osm_mcm_alias_guid_t *) cl_qmap_next(&p_mcm_alias_guid->map_item);
Packit Service 54dbc3
		osm_mcm_alias_guid_delete(&p_mcm_alias_guid);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	p_next_mcm_port =
Packit Service 54dbc3
	    (osm_mcm_port_t *) cl_qmap_head(&p_mgrp->mcm_port_tbl);
Packit Service 54dbc3
	while (p_next_mcm_port !=
Packit Service 54dbc3
	       (osm_mcm_port_t *) cl_qmap_end(&p_mgrp->mcm_port_tbl)) {
Packit Service 54dbc3
		p_mcm_port = p_next_mcm_port;
Packit Service 54dbc3
		p_next_mcm_port =
Packit Service 54dbc3
		    (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item);
Packit Service 54dbc3
		osm_mcm_port_delete(p_mcm_port);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	free(p_mgrp);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_mgrp_box_delete(osm_mgrp_box_t *mbox)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mgrp_t *mgrp;
Packit Service 54dbc3
Packit Service 54dbc3
	while (cl_qlist_count(&mbox->mgrp_list)) {
Packit Service 54dbc3
		mgrp = cl_item_obj(cl_qlist_remove_head(&mbox->mgrp_list),
Packit Service 54dbc3
				   mgrp, list_item);
Packit Service 54dbc3
		mgrp_delete(mgrp);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	mgrp_box_delete(mbox);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
osm_mgrp_t *osm_mgrp_new(IN osm_subn_t * subn, IN ib_net16_t mlid,
Packit Service 54dbc3
			 IN ib_member_rec_t * mcmr)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mgrp_t *p_mgrp;
Packit Service 54dbc3
	osm_mgrp_box_t *mbox;
Packit Service 54dbc3
Packit Service 54dbc3
	p_mgrp = (osm_mgrp_t *) malloc(sizeof(*p_mgrp));
Packit Service 54dbc3
	if (!p_mgrp)
Packit Service 54dbc3
		return NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	memset(p_mgrp, 0, sizeof(*p_mgrp));
Packit Service 54dbc3
	cl_qmap_init(&p_mgrp->mcm_port_tbl);
Packit Service 54dbc3
	cl_qmap_init(&p_mgrp->mcm_alias_port_tbl);
Packit Service 54dbc3
	p_mgrp->mlid = mlid;
Packit Service 54dbc3
	p_mgrp->mcmember_rec = *mcmr;
Packit Service 54dbc3
Packit Service 54dbc3
	mbox = osm_get_mbox_by_mlid(subn, p_mgrp->mlid);
Packit Service 54dbc3
	if (!mbox && !(mbox = mgrp_box_new(cl_ntoh16(p_mgrp->mlid)))) {
Packit Service 54dbc3
		free(p_mgrp);
Packit Service 54dbc3
		return NULL;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	cl_qlist_insert_tail(&mbox->mgrp_list, &p_mgrp->list_item);
Packit Service 54dbc3
	subn->mboxes[mbox->mlid - IB_LID_MCAST_START_HO] = mbox;
Packit Service 54dbc3
Packit Service 54dbc3
	cl_fmap_insert(&subn->mgrp_mgid_tbl, &p_mgrp->mcmember_rec.mgid,
Packit Service 54dbc3
		       &p_mgrp->map_item);
Packit Service 54dbc3
Packit Service 54dbc3
	subn->p_osm->sa.dirty = TRUE;
Packit Service 54dbc3
	return p_mgrp;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_mgrp_cleanup(osm_subn_t * subn, osm_mgrp_t * mgrp)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mgrp_box_t *mbox;
Packit Service 54dbc3
	osm_mcm_alias_guid_t *mcm_alias_guid;
Packit Service 54dbc3
	osm_mcm_port_t *mcm_port;
Packit Service 54dbc3
Packit Service 54dbc3
	if (mgrp->full_members)
Packit Service 54dbc3
		return;
Packit Service 54dbc3
Packit Service 54dbc3
	while (cl_qmap_count(&mgrp->mcm_alias_port_tbl)) {
Packit Service 54dbc3
		mcm_alias_guid = (osm_mcm_alias_guid_t *) cl_qmap_head(&mgrp->mcm_alias_port_tbl);
Packit Service 54dbc3
		cl_qmap_remove_item(&mgrp->mcm_alias_port_tbl, &mcm_alias_guid->map_item);
Packit Service 54dbc3
		osm_mcm_alias_guid_delete(&mcm_alias_guid);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	while (cl_qmap_count(&mgrp->mcm_port_tbl)) {
Packit Service 54dbc3
		mcm_port = (osm_mcm_port_t *) cl_qmap_head(&mgrp->mcm_port_tbl);
Packit Service 54dbc3
		cl_qmap_remove_item(&mgrp->mcm_port_tbl, &mcm_port->map_item);
Packit Service 54dbc3
		cl_qlist_remove_item(&mcm_port->port->mcm_list,
Packit Service 54dbc3
				     &mcm_port->list_item);
Packit Service 54dbc3
		osm_mcm_port_delete(mcm_port);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (mgrp->well_known)
Packit Service 54dbc3
		return;
Packit Service 54dbc3
Packit Service 54dbc3
	cl_fmap_remove_item(&subn->mgrp_mgid_tbl, &mgrp->map_item);
Packit Service 54dbc3
Packit Service 54dbc3
	mbox = osm_get_mbox_by_mlid(subn, mgrp->mlid);
Packit Service 54dbc3
	cl_qlist_remove_item(&mbox->mgrp_list, &mgrp->list_item);
Packit Service 54dbc3
	if (cl_is_qlist_empty(&mbox->mgrp_list)) {
Packit Service 54dbc3
		subn->mboxes[cl_ntoh16(mgrp->mlid) - IB_LID_MCAST_START_HO] = NULL;
Packit Service 54dbc3
		mgrp_box_delete(mbox);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	free(mgrp);
Packit Service 54dbc3
Packit Service 54dbc3
	subn->p_osm->sa.dirty = TRUE;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static void mgrp_send_notice(osm_subn_t * subn, osm_log_t * log,
Packit Service 54dbc3
			     osm_mgrp_t * mgrp, unsigned num)
Packit Service 54dbc3
{
Packit Service 54dbc3
	ib_mad_notice_attr_t notice;
Packit Service 54dbc3
	ib_api_status_t status;
Packit Service 54dbc3
Packit Service 54dbc3
	notice.generic_type = 0x80 | IB_NOTICE_TYPE_SUBN_MGMT;	/* is generic subn mgt type */
Packit Service 54dbc3
	ib_notice_set_prod_type_ho(&notice, 4);	/* A Class Manager generator */
Packit Service 54dbc3
	notice.g_or_v.generic.trap_num = CL_HTON16(num);
Packit Service 54dbc3
	/* The sm_base_lid is saved in network order already. */
Packit Service 54dbc3
	notice.issuer_lid = subn->sm_base_lid;
Packit Service 54dbc3
	/* following o14-12.1.11 and table 120 p726 */
Packit Service 54dbc3
	/* we need to provide the MGID */
Packit Service 54dbc3
	memcpy(&notice.data_details.ntc_64_67.gid,
Packit Service 54dbc3
	       &mgrp->mcmember_rec.mgid, sizeof(ib_gid_t));
Packit Service 54dbc3
Packit Service 54dbc3
	/* According to page 653 - the issuer gid in this case of trap
Packit Service 54dbc3
	   is the SM gid, since the SM is the initiator of this trap. */
Packit Service 54dbc3
	notice.issuer_gid.unicast.prefix = subn->opt.subnet_prefix;
Packit Service 54dbc3
	notice.issuer_gid.unicast.interface_id = subn->sm_port_guid;
Packit Service 54dbc3
Packit Service 54dbc3
	if ((status = osm_report_notice(log, subn, &notice)))
Packit Service 54dbc3
		OSM_LOG(log, OSM_LOG_ERROR, "ERR 7601: "
Packit Service 54dbc3
			"Error sending trap reports (%s)\n",
Packit Service 54dbc3
			ib_get_err_str(status));
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static boolean_t is_qmap_empty_for_port(IN const cl_qmap_t * const p_map,
Packit Service 54dbc3
					IN const osm_port_t *port)
Packit Service 54dbc3
{
Packit Service 54dbc3
	size_t count = 0;
Packit Service 54dbc3
	cl_map_item_t *item;
Packit Service 54dbc3
	osm_mcm_alias_guid_t *mcm_alias_guid;
Packit Service 54dbc3
Packit Service 54dbc3
	for (item = cl_qmap_head(p_map); item != cl_qmap_end(p_map);
Packit Service 54dbc3
	     item = cl_qmap_next(item)) {
Packit Service 54dbc3
		mcm_alias_guid = (osm_mcm_alias_guid_t *) item;
Packit Service 54dbc3
		if (mcm_alias_guid->p_base_mcm_port->port == port) {
Packit Service 54dbc3
			count++;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return (count == 0);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
static boolean_t is_qmap_empty_for_mcm_port(IN const cl_qmap_t * const p_map,
Packit Service 54dbc3
					    IN const osm_mcm_port_t *mcm_port)
Packit Service 54dbc3
{
Packit Service 54dbc3
	size_t count = 0;
Packit Service 54dbc3
	cl_map_item_t *item;
Packit Service 54dbc3
	osm_mcm_alias_guid_t *mcm_alias_guid;
Packit Service 54dbc3
Packit Service 54dbc3
	for (item = cl_qmap_head(p_map); item != cl_qmap_end(p_map);
Packit Service 54dbc3
	     item = cl_qmap_next(item)) {
Packit Service 54dbc3
		mcm_alias_guid = (osm_mcm_alias_guid_t *) item;
Packit Service 54dbc3
		if (mcm_alias_guid->p_base_mcm_port == mcm_port) {
Packit Service 54dbc3
			count++;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	return (count == 0);
Packit Service 54dbc3
}
Packit Service 54dbc3
static osm_mcm_alias_guid_t *insert_alias_guid(IN osm_mgrp_t * mgrp,
Packit Service 54dbc3
					       IN osm_mcm_alias_guid_t * p_mcm_alias_guid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mcm_alias_guid_t *p_mcm_alias_guid_check;
Packit Service 54dbc3
Packit Service 54dbc3
	/* insert into mcm alias guid table */
Packit Service 54dbc3
	p_mcm_alias_guid_check =
Packit Service 54dbc3
		(osm_mcm_alias_guid_t *) cl_qmap_insert(&mgrp->mcm_alias_port_tbl,
Packit Service 54dbc3
							p_mcm_alias_guid->alias_guid,
Packit Service 54dbc3
							&p_mcm_alias_guid->map_item);
Packit Service 54dbc3
	if (p_mcm_alias_guid_check != (osm_mcm_alias_guid_t *) &p_mcm_alias_guid->map_item) {
Packit Service 54dbc3
		/* alias GUID is a duplicate */
Packit Service 54dbc3
		osm_mcm_alias_guid_delete(&p_mcm_alias_guid);
Packit Service 54dbc3
		return p_mcm_alias_guid_check;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	return NULL;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
osm_mcm_port_t *osm_mgrp_add_port(IN osm_subn_t * subn, osm_log_t * log,
Packit Service 54dbc3
				  IN osm_mgrp_t * mgrp, osm_port_t *port,
Packit Service 54dbc3
				  IN ib_member_rec_t *mcmr, IN boolean_t proxy)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mcm_port_t *mcm_port;
Packit Service 54dbc3
	osm_mcm_alias_guid_t *p_mcm_alias_guid, *p_mcm_alias_guid_check;
Packit Service 54dbc3
	cl_map_item_t *prev_item;
Packit Service 54dbc3
	uint8_t prev_join_state = 0, join_state = mcmr->scope_state;
Packit Service 54dbc3
	uint8_t prev_scope, full_join_state;
Packit Service 54dbc3
Packit Service 54dbc3
	if (OSM_LOG_IS_ACTIVE_V2(log, OSM_LOG_VERBOSE)) {
Packit Service 54dbc3
		char gid_str[INET6_ADDRSTRLEN];
Packit Service 54dbc3
		OSM_LOG(log, OSM_LOG_VERBOSE, "GUID 0x%016" PRIx64
Packit Service 54dbc3
			" Port 0x%016" PRIx64 " joining "
Packit Service 54dbc3
			"MC group %s (mlid 0x%x)\n",
Packit Service 54dbc3
			cl_ntoh64(mcmr->port_gid.unicast.interface_id),
Packit Service 54dbc3
			cl_ntoh64(port->guid),
Packit Service 54dbc3
			inet_ntop(AF_INET6, mgrp->mcmember_rec.mgid.raw,
Packit Service 54dbc3
				  gid_str, sizeof(gid_str)),
Packit Service 54dbc3
			cl_ntoh16(mgrp->mlid));
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	mcm_port = osm_mcm_port_new(port, mgrp);
Packit Service 54dbc3
	if (!mcm_port)
Packit Service 54dbc3
		return NULL;
Packit Service 54dbc3
Packit Service 54dbc3
	p_mcm_alias_guid = osm_mcm_alias_guid_new(mcm_port, mcmr, proxy);
Packit Service 54dbc3
	if (!p_mcm_alias_guid) {
Packit Service 54dbc3
		osm_mcm_port_delete(mcm_port);
Packit Service 54dbc3
		return NULL;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	   prev_item = cl_qmap_insert(...)
Packit Service 54dbc3
	   Pointer to the item in the map with the specified key.  If insertion
Packit Service 54dbc3
	   was successful, this is the pointer to the item.  If an item with the
Packit Service 54dbc3
	   specified key already exists in the map, the pointer to that item is
Packit Service 54dbc3
	   returned.
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	prev_item = cl_qmap_insert(&mgrp->mcm_port_tbl, port->guid,
Packit Service 54dbc3
				   &mcm_port->map_item);
Packit Service 54dbc3
Packit Service 54dbc3
	if (prev_item != &mcm_port->map_item) {	/* mcm port already exists */
Packit Service 54dbc3
		osm_mcm_port_delete(mcm_port);
Packit Service 54dbc3
		mcm_port = (osm_mcm_port_t *) prev_item;
Packit Service 54dbc3
Packit Service 54dbc3
		p_mcm_alias_guid->p_base_mcm_port = (osm_mcm_port_t *) prev_item;
Packit Service 54dbc3
		p_mcm_alias_guid_check = insert_alias_guid(mgrp, p_mcm_alias_guid);
Packit Service 54dbc3
		if (p_mcm_alias_guid_check) {	/* alias GUID already exists */
Packit Service 54dbc3
			p_mcm_alias_guid = p_mcm_alias_guid_check;
Packit Service 54dbc3
			ib_member_get_scope_state(p_mcm_alias_guid->scope_state,
Packit Service 54dbc3
						  &prev_scope, &prev_join_state);
Packit Service 54dbc3
			p_mcm_alias_guid->scope_state =
Packit Service 54dbc3
			    ib_member_set_scope_state(prev_scope,
Packit Service 54dbc3
						      prev_join_state | join_state);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		insert_alias_guid(mgrp, p_mcm_alias_guid);
Packit Service 54dbc3
		cl_qlist_insert_tail(&port->mcm_list, &mcm_port->list_item);
Packit Service 54dbc3
		osm_sm_reroute_mlid(&subn->p_osm->sm, mgrp->mlid);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* o15.0.1.11: copy the join state */
Packit Service 54dbc3
	mcmr->scope_state = p_mcm_alias_guid->scope_state;
Packit Service 54dbc3
Packit Service 54dbc3
	full_join_state = IB_JOIN_STATE_FULL | IB_JOIN_STATE_SEND_ONLY_FULL;
Packit Service 54dbc3
	if ((join_state & full_join_state) && !(prev_join_state & full_join_state) &&
Packit Service 54dbc3
	    ++mgrp->full_members == 1)
Packit Service 54dbc3
		mgrp_send_notice(subn, log, mgrp, SM_MGID_CREATED_TRAP); /* 66 */
Packit Service 54dbc3
Packit Service 54dbc3
	subn->p_osm->sa.dirty = TRUE;
Packit Service 54dbc3
	return mcm_port;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
boolean_t osm_mgrp_remove_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp,
Packit Service 54dbc3
			  osm_mcm_alias_guid_t * mcm_alias_guid,
Packit Service 54dbc3
			  ib_member_rec_t *mcmr)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint8_t join_state = mcmr->scope_state & 0xf;
Packit Service 54dbc3
	uint8_t port_join_state, new_join_state, full_join_state;
Packit Service 54dbc3
	boolean_t mgrp_deleted = FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
	/*
Packit Service 54dbc3
	 * according to the same o15-0.1.14 we get the stored
Packit Service 54dbc3
	 * JoinState and the request JoinState and they must be
Packit Service 54dbc3
	 * opposite to leave - otherwise just update it
Packit Service 54dbc3
	 */
Packit Service 54dbc3
	port_join_state = mcm_alias_guid->scope_state & 0x0F;
Packit Service 54dbc3
	new_join_state = port_join_state & ~join_state;
Packit Service 54dbc3
Packit Service 54dbc3
	if (OSM_LOG_IS_ACTIVE_V2(log, OSM_LOG_VERBOSE)) {
Packit Service 54dbc3
		char gid_str[INET6_ADDRSTRLEN];
Packit Service 54dbc3
		OSM_LOG(log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
			"GUID 0x%" PRIx64 " Port 0x%" PRIx64
Packit Service 54dbc3
			" leaving MC group %s (mlid 0x%x)\n",
Packit Service 54dbc3
			cl_ntoh64(mcm_alias_guid->alias_guid),
Packit Service 54dbc3
			cl_ntoh64(mcm_alias_guid->p_base_mcm_port->port->guid),
Packit Service 54dbc3
			inet_ntop(AF_INET6, mgrp->mcmember_rec.mgid.raw,
Packit Service 54dbc3
				  gid_str, sizeof(gid_str)),
Packit Service 54dbc3
			cl_ntoh16(mgrp->mlid));
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (new_join_state & IB_JOIN_STATE_FULL ||
Packit Service 54dbc3
	    (new_join_state &&
Packit Service 54dbc3
	     (mgrp->full_members > (port_join_state & IB_JOIN_STATE_FULL) ? 1 : 0))) {
Packit Service 54dbc3
		mcm_alias_guid->scope_state =
Packit Service 54dbc3
		    new_join_state | (mcm_alias_guid->scope_state & 0xf0);
Packit Service 54dbc3
		OSM_LOG(log, OSM_LOG_DEBUG,
Packit Service 54dbc3
			"updating GUID 0x%" PRIx64 " port 0x%" PRIx64
Packit Service 54dbc3
			" JoinState 0x%x -> 0x%x\n",
Packit Service 54dbc3
			cl_ntoh64(mcm_alias_guid->alias_guid),
Packit Service 54dbc3
			cl_ntoh64(mcm_alias_guid->p_base_mcm_port->port->guid),
Packit Service 54dbc3
			port_join_state, new_join_state);
Packit Service 54dbc3
		mcmr->scope_state = mcm_alias_guid->scope_state;
Packit Service 54dbc3
	} else {
Packit Service 54dbc3
		mcmr->scope_state = mcm_alias_guid->scope_state & 0xf0;
Packit Service 54dbc3
		OSM_LOG(log, OSM_LOG_DEBUG, "removing alias GUID 0x%" PRIx64 "\n",
Packit Service 54dbc3
			cl_ntoh64(mcm_alias_guid->alias_guid));
Packit Service 54dbc3
		cl_qmap_remove_item(&mgrp->mcm_alias_port_tbl,
Packit Service 54dbc3
				    &mcm_alias_guid->map_item);
Packit Service 54dbc3
		if (is_qmap_empty_for_port(&mgrp->mcm_alias_port_tbl,
Packit Service 54dbc3
					   mcm_alias_guid->p_base_mcm_port->port)) { /* last alias in mcast group for this port */
Packit Service 54dbc3
			OSM_LOG(log, OSM_LOG_DEBUG, "removing port 0x%" PRIx64 "\n",
Packit Service 54dbc3
				cl_ntoh64(mcm_alias_guid->p_base_mcm_port->port->guid));
Packit Service 54dbc3
			cl_qmap_remove_item(&mgrp->mcm_port_tbl,
Packit Service 54dbc3
					    &mcm_alias_guid->p_base_mcm_port->map_item);
Packit Service 54dbc3
			cl_qlist_remove_item(&mcm_alias_guid->p_base_mcm_port->port->mcm_list,
Packit Service 54dbc3
					     &mcm_alias_guid->p_base_mcm_port->list_item);
Packit Service 54dbc3
			if (is_qmap_empty_for_mcm_port(&mgrp->mcm_alias_port_tbl,
Packit Service 54dbc3
						       mcm_alias_guid->p_base_mcm_port)) /* last alias in mcast group for this mcm port */
Packit Service 54dbc3
				osm_mcm_port_delete(mcm_alias_guid->p_base_mcm_port);
Packit Service 54dbc3
			osm_sm_reroute_mlid(&subn->p_osm->sm, mgrp->mlid);
Packit Service 54dbc3
		}
Packit Service 54dbc3
		osm_mcm_alias_guid_delete(&mcm_alias_guid);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	full_join_state = IB_JOIN_STATE_FULL | IB_JOIN_STATE_SEND_ONLY_FULL;
Packit Service 54dbc3
Packit Service 54dbc3
	/* no more full members so the group will be deleted after re-route
Packit Service 54dbc3
	   but only if it is not a well known group */
Packit Service 54dbc3
	if ((port_join_state & full_join_state) && !(new_join_state & full_join_state) &&
Packit Service 54dbc3
	    --mgrp->full_members == 0) {
Packit Service 54dbc3
		mgrp_send_notice(subn, log, mgrp, SM_MGID_DESTROYED_TRAP); /* 67 */
Packit Service 54dbc3
		osm_mgrp_cleanup(subn, mgrp);
Packit Service 54dbc3
		mgrp_deleted = TRUE;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	subn->p_osm->sa.dirty = TRUE;
Packit Service 54dbc3
Packit Service 54dbc3
	return (mgrp_deleted);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void osm_mgrp_delete_port(osm_subn_t * subn, osm_log_t * log, osm_mgrp_t * mgrp,
Packit Service 54dbc3
			  osm_port_t * port)
Packit Service 54dbc3
{
Packit Service 54dbc3
	osm_mcm_alias_guid_t *mcm_alias_guid, *next_mcm_alias_guid;
Packit Service 54dbc3
	ib_member_rec_t mcmrec;
Packit Service 54dbc3
	boolean_t mgrp_deleted = FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
	next_mcm_alias_guid = (osm_mcm_alias_guid_t *) cl_qmap_head(&mgrp->mcm_alias_port_tbl);
Packit Service 54dbc3
	while (!mgrp_deleted &&
Packit Service 54dbc3
	       next_mcm_alias_guid != (osm_mcm_alias_guid_t *) cl_qmap_end(&mgrp->mcm_alias_port_tbl)) {
Packit Service 54dbc3
		mcm_alias_guid = next_mcm_alias_guid;
Packit Service 54dbc3
		next_mcm_alias_guid = (osm_mcm_alias_guid_t *) cl_qmap_next(&next_mcm_alias_guid->map_item);
Packit Service 54dbc3
		if (mcm_alias_guid->p_base_mcm_port->port == port) {
Packit Service 54dbc3
			mcmrec.scope_state = 0xf;
Packit Service 54dbc3
			mgrp_deleted = osm_mgrp_remove_port(subn, log, mgrp, mcm_alias_guid,
Packit Service 54dbc3
					     &mcmrec);
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
osm_mcm_port_t *osm_mgrp_get_mcm_port(IN const osm_mgrp_t * p_mgrp,
Packit Service 54dbc3
				      IN ib_net64_t port_guid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cl_map_item_t *item = cl_qmap_get(&p_mgrp->mcm_port_tbl, port_guid);
Packit Service 54dbc3
	if (item != cl_qmap_end(&p_mgrp->mcm_port_tbl))
Packit Service 54dbc3
		return (osm_mcm_port_t *) item;
Packit Service 54dbc3
	return NULL;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
osm_mcm_alias_guid_t *osm_mgrp_get_mcm_alias_guid(IN const osm_mgrp_t * p_mgrp,
Packit Service 54dbc3
						  IN ib_net64_t port_guid)
Packit Service 54dbc3
{
Packit Service 54dbc3
	cl_map_item_t *item = cl_qmap_get(&p_mgrp->mcm_alias_port_tbl,
Packit Service 54dbc3
					  port_guid);
Packit Service 54dbc3
	if (item != cl_qmap_end(&p_mgrp->mcm_alias_port_tbl))
Packit Service 54dbc3
		return (osm_mcm_alias_guid_t *) item;
Packit Service 54dbc3
	return NULL;
Packit Service 54dbc3
}