Exemplo n.º 1
0
ib_api_status_t osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl,
					       IN uint16_t * p_pkey,
					       OUT uint16_t * p_block_idx,
					       OUT uint8_t * p_pkey_idx)
{
	uint16_t num_of_blocks;
	uint16_t block_index;
	ib_pkey_table_t *block;

	CL_ASSERT(p_block_idx != NULL);
	CL_ASSERT(p_pkey_idx != NULL);

	num_of_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->blocks);
	for (block_index = 0; block_index < num_of_blocks; block_index++) {
		block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index);
		if ((block->pkey_entry <= p_pkey) &&
		    (p_pkey <
		     block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) {
			*p_block_idx = block_index;
			*p_pkey_idx = (uint8_t) (p_pkey - block->pkey_entry);
			return IB_SUCCESS;
		}
	}
	return IB_NOT_FOUND;
}
Exemplo n.º 2
0
void osm_pkey_tbl_init_new_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl)
{
	ib_pkey_table_t *p_block;
	size_t b, num_blocks = cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks);

	for (b = 0; b < num_blocks; b++)
		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, b)))
			memset(p_block, 0, sizeof(*p_block));
}
Exemplo n.º 3
0
void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl)
{
	ib_pkey_table_t *p_block;
	uint16_t num_blocks, i;

	num_blocks = (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks));
	for (i = 0; i < num_blocks; i++)
		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, i)))
			free(p_block);
	cl_ptr_vector_destroy(&p_pkey_tbl->blocks);

	num_blocks =
	    (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks));
	for (i = 0; i < num_blocks; i++)
		if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, i)))
			free(p_block);
	cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks);

	cl_map_remove_all(&p_pkey_tbl->accum_pkeys);
	cl_map_destroy(&p_pkey_tbl->accum_pkeys);

	cl_map_remove_all(&p_pkey_tbl->keys);
	cl_map_destroy(&p_pkey_tbl->keys);
}
Exemplo n.º 4
0
/**********************************************************************
 Clear out all existing port lid assignments
**********************************************************************/
static ib_api_status_t state_mgr_clean_known_lids(IN osm_sm_t * sm)
{
	ib_api_status_t status = IB_SUCCESS;
	cl_ptr_vector_t *p_vec = &(sm->p_subn->port_lid_tbl);
	uint32_t i;

	OSM_LOG_ENTER(sm->p_log);

	/* we need a lock here! */
	CL_PLOCK_ACQUIRE(sm->p_lock);

	for (i = 0; i < cl_ptr_vector_get_size(p_vec); i++)
		cl_ptr_vector_set(p_vec, i, NULL);

	CL_PLOCK_RELEASE(sm->p_lock);

	OSM_LOG_EXIT(sm->p_log);
	return status;
}
Exemplo n.º 5
0
static int ucast_mgr_setup_all_switches(osm_subn_t * p_subn)
{
	osm_switch_t *p_sw;
	uint16_t lids;

	lids = (uint16_t) cl_ptr_vector_get_size(&p_subn->port_lid_tbl);
	lids = lids ? lids - 1 : 0;

	for (p_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
	     p_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl);
	     p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item))
		if (osm_switch_prepare_path_rebuild(p_sw, lids)) {
			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A0B: "
				"cannot setup switch 0x%016" PRIx64 "\n",
				cl_ntoh64(osm_node_get_node_guid
					  (p_sw->p_node)));
			return -1;
		}

	return 0;
}
Exemplo n.º 6
0
static int ucast_mgr_setup_all_switches(osm_subn_t * p_subn)
{
	osm_switch_t *p_sw;
	uint16_t lids;

	lids = (uint16_t) cl_ptr_vector_get_size(&p_subn->port_lid_tbl);
	lids = lids ? lids - 1 : 0;

	for (p_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl);
	     p_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl);
	     p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) {
		if (osm_switch_prepare_path_rebuild(p_sw, lids)) {
			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A0B: "
				"cannot setup switch 0x%016" PRIx64 "\n",
				cl_ntoh64(osm_node_get_node_guid
					  (p_sw->p_node)));
			return -1;
		}
		if (p_sw->search_ordering_ports) {
			free(p_sw->search_ordering_ports);
			p_sw->search_ordering_ports = NULL;
		}
	}

	if (p_subn->opt.port_search_ordering_file) {
		OSM_LOG(&p_subn->p_osm->log, OSM_LOG_DEBUG,
			"Fetching dimension ports file \'%s\'\n",
			p_subn->opt.port_search_ordering_file);
		if (parse_node_map(p_subn->opt.port_search_ordering_file,
				   set_search_ordering_ports, p_subn)) {
			OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A0F: "
				"cannot parse port_search_ordering_file \'%s\'\n",
				p_subn->opt.port_search_ordering_file);
		}
	}

	return 0;
}
Exemplo n.º 7
0
/**********************************************************************
o13-14.1.1: Except for Set(InformInfo) requests with Inform-
Info:LIDRangeBegin=0xFFFF, managers that support event forwarding
shall, upon receiving a Set(InformInfo), verify that the requester
originating the Set(InformInfo) and a Trap() source identified by Inform-
can access each other - can use path record to verify that.
**********************************************************************/
static boolean_t
__validate_ports_access_rights(IN osm_sa_t * sa,
			       IN osm_infr_t * p_infr_rec)
{
	boolean_t valid = TRUE;
	osm_physp_t *p_requester_physp;
	osm_port_t *p_port;
	osm_physp_t *p_physp;
	ib_net64_t portguid;
	ib_net16_t lid_range_begin;
	ib_net16_t lid_range_end;
	ib_net16_t lid;
	const cl_ptr_vector_t *p_tbl;
	ib_gid_t zero_gid;

	OSM_LOG_ENTER(sa->p_log);

	/* get the requester physp from the request address */
	p_requester_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
						      &p_infr_rec->report_addr);

	memset(&zero_gid, 0, sizeof(zero_gid));
	if (memcmp(&(p_infr_rec->inform_record.inform_info.gid),
		   &zero_gid, sizeof(ib_gid_t))) {
		/* a gid is defined */
		portguid =
		    p_infr_rec->inform_record.inform_info.gid.unicast.
		    interface_id;

		p_port = osm_get_port_by_guid(sa->p_subn, portguid);

		if (p_port == NULL) {
			OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4301: "
				"Invalid port guid: 0x%016" PRIx64 "\n",
				cl_ntoh64(portguid));
			valid = FALSE;
			goto Exit;
		}

		/* get the destination InformInfo physical port */
		p_physp = p_port->p_physp;

		/* make sure that the requester and destination port can access each other
		   according to the current partitioning. */
		if (!osm_physp_share_pkey
		    (sa->p_log, p_physp, p_requester_physp)) {
			OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
				"port and requester don't share pkey\n");
			valid = FALSE;
			goto Exit;
		}
	} else {
		/* gid is zero - check if LID range is defined */
		lid_range_begin =
		    cl_ntoh16(p_infr_rec->inform_record.inform_info.
			      lid_range_begin);
		/* if lid is 0xFFFF - meaning all endports managed by the manager */
		if (lid_range_begin == 0xFFFF)
			goto Exit;

		lid_range_end =
		    cl_ntoh16(p_infr_rec->inform_record.inform_info.
			      lid_range_end);

		/* lid_range_end is set to zero if no range desired. In this case -
		   just make it equal to the lid_range_begin. */
		if (lid_range_end == 0)
			lid_range_end = lid_range_begin;

		/* go over all defined lids within the range and make sure that the
		   requester port can access them according to current partitioning. */
		for (lid = lid_range_begin; lid <= lid_range_end; lid++) {
			p_tbl = &sa->p_subn->port_lid_tbl;
			if (cl_ptr_vector_get_size(p_tbl) > lid)
				p_port = cl_ptr_vector_get(p_tbl, lid);
			else {
				/* lid requested is out of range */
				OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4302: "
					"Given LID (%u) is out of range:%u\n",
					lid, cl_ptr_vector_get_size(p_tbl));
				valid = FALSE;
				goto Exit;
			}
			if (p_port == NULL)
				continue;

			p_physp = p_port->p_physp;
			/* make sure that the requester and destination port can access
			   each other according to the current partitioning. */
			if (!osm_physp_share_pkey
			    (sa->p_log, p_physp, p_requester_physp)) {
				OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
					"port and requester don't share pkey\n");
				valid = FALSE;
				goto Exit;
			}
		}
	}

Exit:
	OSM_LOG_EXIT(sa->p_log);
	return valid;
}
Exemplo n.º 8
0
/** ===========================================================================
 */
static int
extract_alloc_tbls(osm_subn_t *p_subn, struct ssa_db_extract *p_ssa_db)
{
	const osm_pkey_tbl_t *p_pkey_tbl;
	osm_switch_t *p_sw;
	osm_port_t *p_port;
	uint64_t links, ports, lft_blocks;
	uint32_t guids, nodes, lft_tops;
	uint32_t switch_ports_num = 0;
	uint32_t pkey_cnt = 0;
	uint16_t lids;

	nodes = (uint32_t) cl_qmap_count(&p_subn->node_guid_tbl);
	if (!p_ssa_db->p_node_tbl) {
		p_ssa_db->p_node_tbl = (struct smdb_node *)
		    malloc(sizeof(*p_ssa_db->p_node_tbl) * nodes);
		if (!p_ssa_db->p_node_tbl) {
			ssa_log(SSA_LOG_DEFAULT,
				"ERROR - unable to allocate nodes table\n");
			goto err0;
		}
	}

	lft_tops = (uint32_t) cl_qmap_count(&p_subn->sw_guid_tbl);
	if (!ssa_db->p_lft_db->p_db_lft_top_tbl) {
		ssa_db->p_lft_db->p_db_lft_top_tbl = (struct smdb_lft_top *)
			malloc(sizeof(*ssa_db->p_lft_db->p_db_lft_top_tbl) *
			       lft_tops);
		if (!ssa_db->p_lft_db->p_db_lft_top_tbl) {
			ssa_log(SSA_LOG_DEFAULT,
				"ERROR - unable to allocate LFT tops table\n");
			goto err1;
		}
	}

	lids = (uint16_t) cl_ptr_vector_get_size(&p_subn->port_lid_tbl);

	lft_blocks = ((lids % IB_SMP_DATA_SIZE) ?
	    (lids / IB_SMP_DATA_SIZE + 1) : (lids / IB_SMP_DATA_SIZE));
	lft_blocks = (uint64_t) lft_tops * lft_blocks * (1 << p_ssa_db->lmc);
	if (!ssa_db->p_lft_db->p_db_lft_block_tbl) {
		ssa_db->p_lft_db->p_db_lft_block_tbl =
		    (struct smdb_lft_block *)
			malloc(sizeof(*ssa_db->p_lft_db->p_db_lft_block_tbl) *
			       lft_blocks);
		if (!ssa_db->p_lft_db->p_db_lft_block_tbl) {
			ssa_log(SSA_LOG_DEFAULT,
				"ERROR - unable to allocate LFT blocks table\n");
			goto err2;
		}
	}

	guids = (uint32_t) cl_qmap_count(&p_subn->port_guid_tbl);
	if (!p_ssa_db->p_guid_to_lid_tbl) {
		p_ssa_db->p_guid_to_lid_tbl = (struct smdb_guid2lid *)
				malloc(sizeof(*p_ssa_db->p_guid_to_lid_tbl) *
				       guids);
		if (!p_ssa_db->p_guid_to_lid_tbl) {
			ssa_log(SSA_LOG_DEFAULT,
				"ERROR - unable to allocate GUID to LID table\n");
			goto err3;
		}
	}

	for (p_sw = (osm_switch_t *)cl_qmap_head(&p_subn->sw_guid_tbl);
	     p_sw != (osm_switch_t *)cl_qmap_end(&p_subn->sw_guid_tbl);
	     p_sw = (osm_switch_t *)cl_qmap_next(&p_sw->map_item))
			switch_ports_num += p_sw->num_ports;

	links = guids + switch_ports_num;
	if (!p_ssa_db->p_link_tbl) {
		p_ssa_db->p_link_tbl = (struct smdb_link *)
				malloc(sizeof(*p_ssa_db->p_link_tbl) * links);
		if (!p_ssa_db->p_link_tbl) {
			ssa_log(SSA_LOG_DEFAULT,
				"ERROR - unable to allocate links table\n");
			goto err4;
		}
	}

	ports = links;
	if (!p_ssa_db->p_port_tbl) {
		p_ssa_db->p_port_tbl = (struct smdb_port *)
				malloc(sizeof(*p_ssa_db->p_port_tbl) * ports);
		if (!p_ssa_db->p_port_tbl) {
			ssa_log(SSA_LOG_DEFAULT,
				"ERROR - unable to allocate ports table\n");
			goto err5;
		}
	}

	for (p_port = (osm_port_t *)cl_qmap_head(&p_subn->port_guid_tbl);
	     p_port != (osm_port_t *)cl_qmap_end(&p_subn->port_guid_tbl);
	     p_port = (osm_port_t *)cl_qmap_next(&p_port->map_item)) {
		p_pkey_tbl = osm_physp_get_pkey_tbl(p_port->p_physp);
		pkey_cnt += (uint32_t)
		    cl_map_count((const cl_map_t *) &p_pkey_tbl->keys);
	}

	if (!p_ssa_db->p_pkey_tbl) {
		p_ssa_db->p_pkey_tbl = (uint16_t *)
		    malloc(sizeof(*p_ssa_db->p_pkey_tbl) * pkey_cnt);
		if (!p_ssa_db->p_pkey_tbl) {
			ssa_log(SSA_LOG_DEFAULT,
				"ERROR - unable to allocate pkeys table\n");
			goto err6;
		}
	}
	p_ssa_db->pkey_tbl_rec_num = pkey_cnt;

	return 0;

err6:
	free(p_ssa_db->p_port_tbl);
err5:
	free(p_ssa_db->p_link_tbl);
err4:
	free(p_ssa_db->p_guid_to_lid_tbl);
err3:
	free(ssa_db->p_lft_db->p_db_lft_block_tbl);
err2:
	free(ssa_db->p_lft_db->p_db_lft_top_tbl);
err1:
	free(p_ssa_db->p_node_tbl);
err0:
	return -1;
}
Exemplo n.º 9
0
ib_api_status_t osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl,
				 IN uint16_t block, IN ib_pkey_table_t * p_tbl,
				 IN boolean_t allow_both_pkeys)
{
	uint16_t b, i;
	ib_pkey_table_t *p_pkey_block;
	uint16_t *p_prev_pkey;
	ib_net16_t pkey, pkey_base;

	/* make sure the block is allocated */
	if (cl_ptr_vector_get_size(&p_pkey_tbl->blocks) > block)
		p_pkey_block =
		    (ib_pkey_table_t *) cl_ptr_vector_get(&p_pkey_tbl->blocks,
							  block);
	else
		p_pkey_block = NULL;

	if (!p_pkey_block) {
		p_pkey_block =
		    (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t));
		if (!p_pkey_block)
			return IB_ERROR;
		memset(p_pkey_block, 0, sizeof(ib_pkey_table_t));
		cl_ptr_vector_set(&p_pkey_tbl->blocks, block, p_pkey_block);
	}

	/* sets the block values */
	memcpy(p_pkey_block, p_tbl, sizeof(ib_pkey_table_t));

	/*
	   NOTE: as the spec does not require uniqueness of PKeys in
	   tables there is no other way but to refresh the entire keys map.

	   Moreover, if the same key exists but with full membership it should
	   have precedence over the key with limited membership !
	 */
	cl_map_remove_all(&p_pkey_tbl->keys);

	for (b = 0; b < cl_ptr_vector_get_size(&p_pkey_tbl->blocks); b++) {

		p_pkey_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, b);
		if (!p_pkey_block)
			continue;

		for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) {
			pkey = p_pkey_block->pkey_entry[i];
			if (ib_pkey_is_invalid(pkey))
				continue;

			if (allow_both_pkeys)
				pkey_base = pkey;
			else
				pkey_base = ib_pkey_get_base(pkey);

			/*
			   If allow_both_pkeys is FALSE,
			   ignore the PKey Full Member bit in the key but store
			   the pointer to the table element as the map value
			 */
			p_prev_pkey = cl_map_get(&p_pkey_tbl->keys, pkey_base);

			/* we only insert if no previous or it is not full member and allow_both_pkeys is FALSE */
			if ((p_prev_pkey == NULL) ||
			    (allow_both_pkeys == FALSE &&
			     cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey)))
				cl_map_insert(&p_pkey_tbl->keys, pkey_base,
					      &(p_pkey_block->pkey_entry[i])
				    );
		}
	}
	return IB_SUCCESS;
}
Exemplo n.º 10
0
/**********************************************************************
 * Make sure that the lid_port_tbl of the subnet has only the ports
 * that are recognized, and in the correct lid place. There could be
 * errors if we wanted to assign a certain port with lid X, but that
 * request didn't reach the port. In this case port_lid_tbl will have
 * the port under lid X, though the port isn't updated with this lid.
 * We will run a new heavy sweep (since there were errors in the
 * initialization), but here we'll clean the database from incorrect
 * information.
 **********************************************************************/
static void state_mgr_check_tbl_consistency(IN osm_sm_t * sm)
{
	cl_qmap_t *p_port_guid_tbl;
	osm_port_t *p_port;
	osm_port_t *p_next_port;
	cl_ptr_vector_t *p_port_lid_tbl;
	size_t max_lid, ref_size, curr_size, lid;
	osm_port_t *p_port_ref, *p_port_stored;
	cl_ptr_vector_t ref_port_lid_tbl;
	uint16_t min_lid_ho;
	uint16_t max_lid_ho;
	uint16_t lid_ho;

	OSM_LOG_ENTER(sm->p_log);

	cl_ptr_vector_construct(&ref_port_lid_tbl);
	cl_ptr_vector_init(&ref_port_lid_tbl,
			   cl_ptr_vector_get_size(&sm->p_subn->port_lid_tbl),
			   OSM_SUBNET_VECTOR_GROW_SIZE);

	p_port_guid_tbl = &sm->p_subn->port_guid_tbl;

	/* Let's go over all the ports according to port_guid_tbl,
	 * and add the port to a reference port_lid_tbl. */
	p_next_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl);
	while (p_next_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl)) {
		p_port = p_next_port;
		p_next_port =
		    (osm_port_t *) cl_qmap_next(&p_next_port->map_item);

		osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho);
		for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++)
			cl_ptr_vector_set(&ref_port_lid_tbl, lid_ho, p_port);
	}

	p_port_lid_tbl = &sm->p_subn->port_lid_tbl;

	ref_size = cl_ptr_vector_get_size(&ref_port_lid_tbl);
	curr_size = cl_ptr_vector_get_size(p_port_lid_tbl);
	/* They should be the same, but compare it anyway */
	max_lid = (ref_size > curr_size) ? ref_size : curr_size;

	for (lid = 1; lid < max_lid; lid++) {
		p_port_ref = NULL;
		p_port_stored = NULL;
		cl_ptr_vector_at(p_port_lid_tbl, lid, (void *)&p_port_stored);
		cl_ptr_vector_at(&ref_port_lid_tbl, lid, (void *)&p_port_ref);

		if (p_port_stored == p_port_ref)
			/* This is the "good" case - both entries are the
			 * same for this lid. Nothing to do. */
			continue;

		if (p_port_ref == NULL)
			/* There is an object in the subnet database for this
			 * lid, but no such object exists in the reference
			 * port_list_tbl. This can occur if we wanted to assign
			 * a certain port with some lid (different than the one
			 * pre-assigned to it), and the port didn't get the
			 * PortInfo Set request. Due to this, the port is
			 * updated with its original lid in our database, but
			 * with the new lid we wanted to give it in our
			 * port_lid_tbl. */
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3322: "
				"lid %zu is wrongly assigned to port 0x%016"
				PRIx64 " (\'%s\' port %u) in port_lid_tbl\n",
				lid,
				cl_ntoh64(osm_port_get_guid(p_port_stored)),
				p_port_stored->p_node->print_desc,
				p_port_stored->p_physp->port_num);
		else if (p_port_stored == NULL)
			/* There is an object in the new database, but no
			 * object in our subnet database. This is the matching
			 * case of the prior check - the port still has its
			 * original lid. */
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3323: "
				"port 0x%016" PRIx64 " (\'%s\' port %u)"
				" exists in new port_lid_tbl under lid %zu,"
				" but missing in subnet port_lid_tbl db\n",
				cl_ntoh64(osm_port_get_guid(p_port_ref)),
				p_port_ref->p_node->print_desc,
				p_port_ref->p_physp->port_num, lid);
		else
			/* if we reached here then p_port_stored != p_port_ref.
			 * We were trying to set a lid to p_port_stored, but
			 * it didn't reach it, and p_port_ref also didn't get
			 * the lid update. */
			OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3324: "
				"lid %zu has port 0x%016" PRIx64
				" (\'%s\' port %u) in new port_lid_tbl db, "
				"and port 0x%016" PRIx64 " (\'%s\' port %u)"
				" in subnet port_lid_tbl db\n", lid,
				cl_ntoh64(osm_port_get_guid(p_port_ref)),
				p_port_ref->p_node->print_desc,
				p_port_ref->p_physp->port_num,
				cl_ntoh64(osm_port_get_guid(p_port_stored)),
				p_port_ref->p_node->print_desc,
				p_port_ref->p_physp->port_num);

		/* In any of these cases we want to set NULL in the
		 * port_lid_tbl, since this entry is invalid. Also, make sure
		 * we'll do another heavy sweep. */
		cl_ptr_vector_set(p_port_lid_tbl, lid, NULL);
		sm->p_subn->subnet_initialization_error = TRUE;
	}

	cl_ptr_vector_destroy(&ref_port_lid_tbl);
	OSM_LOG_EXIT(sm->p_log);
}
Exemplo n.º 11
0
/* Find Root nodes automatically by Min Hop Table info */
static void updn_find_root_nodes_by_min_hop(OUT updn_t * p_updn)
{
	osm_opensm_t *p_osm = p_updn->p_osm;
	osm_switch_t *p_sw;
	osm_port_t *p_port;
	osm_physp_t *p_physp;
	cl_map_item_t *item;
	double thd1, thd2;
	unsigned i, cas_num = 0;
	unsigned *cas_per_sw;
	uint16_t lid_ho;

	OSM_LOG_ENTER(&p_osm->log);

	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
		"Current number of ports in the subnet is %d\n",
		cl_qmap_count(&p_osm->subn.port_guid_tbl));

	lid_ho = (uint16_t) cl_ptr_vector_get_size(&p_updn->p_osm->subn.port_lid_tbl) + 1;
	cas_per_sw = malloc(lid_ho * sizeof(*cas_per_sw));
	if (!cas_per_sw) {
		OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR AA14: "
			"cannot alloc mem for CAs per switch counter array\n");
		goto _exit;
	}
	memset(cas_per_sw, 0, lid_ho * sizeof(*cas_per_sw));

	/* Find the Maximum number of CAs (and routers) for histogram normalization */
	OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
		"Finding the number of CAs and storing them in cl_map\n");
	for (item = cl_qmap_head(&p_updn->p_osm->subn.port_guid_tbl);
	     item != cl_qmap_end(&p_updn->p_osm->subn.port_guid_tbl);
	     item = cl_qmap_next(item)) {
		p_port = (osm_port_t *)item;
		if (!p_port->p_node->sw) {
			p_physp = p_port->p_physp->p_remote_physp;
			if (!p_physp || !p_physp->p_node->sw)
				continue;
			lid_ho = osm_node_get_base_lid(p_physp->p_node, 0);
			lid_ho = cl_ntoh16(lid_ho);
			cas_per_sw[lid_ho]++;
			cas_num++;
		}
	}

	thd1 = cas_num * 0.9;
	thd2 = cas_num * 0.05;
	OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
		"Found %u CAs and RTRs, %u SWs in the subnet. "
		"Thresholds are thd1 = %f && thd2 = %f\n",
		cas_num, cl_qmap_count(&p_osm->subn.sw_guid_tbl), thd1, thd2);

	OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
		"Passing through all switches to collect Min Hop info\n");
	for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
	     item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
	     item = cl_qmap_next(item)) {
		unsigned hop_hist[IB_SUBNET_PATH_HOPS_MAX];
		uint16_t max_lid_ho;
		uint8_t hop_val;
		uint16_t numHopBarsOverThd1 = 0;
		uint16_t numHopBarsOverThd2 = 0;

		p_sw = (osm_switch_t *) item;

		memset(hop_hist, 0, sizeof(hop_hist));

		max_lid_ho = p_sw->max_lid_ho;
		for (lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++)
			if (cas_per_sw[lid_ho]) {
				hop_val =
				    osm_switch_get_least_hops(p_sw, lid_ho);
				if (hop_val >= IB_SUBNET_PATH_HOPS_MAX)
					continue;

				hop_hist[hop_val] += cas_per_sw[lid_ho];
			}

		/* Now recognize the spines by requiring one bar to be
		   above 90% of the number of CAs and RTRs */
		for (i = 0; i < IB_SUBNET_PATH_HOPS_MAX; i++) {
			if (hop_hist[i] > thd1)
				numHopBarsOverThd1++;
			if (hop_hist[i] > thd2)
				numHopBarsOverThd2++;
		}

		/* If thd conditions are valid - rank the root node */
		if (numHopBarsOverThd1 == 1 && numHopBarsOverThd2 == 1) {
			OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
				"Ranking GUID 0x%" PRIx64 " as root node\n",
				cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
			((struct updn_node *)p_sw->priv)->rank = 0;
			p_updn->num_roots++;
		}
	}

	free(cas_per_sw);
_exit:
	OSM_LOG_EXIT(&p_osm->log);
	return;
}