|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 2002-2007,2009 Mellanox Technologies LTD. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 2009 HNR Consulting. All rights reserved.
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* This software is available to you under a choice of one of two
|
|
Packit |
13e616 |
* licenses. You may choose to be licensed under the terms of the GNU
|
|
Packit |
13e616 |
* General Public License (GPL) Version 2, available from the file
|
|
Packit |
13e616 |
* COPYING in the main directory of this source tree, or the
|
|
Packit |
13e616 |
* OpenIB.org BSD license below:
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* Redistribution and use in source and binary forms, with or
|
|
Packit |
13e616 |
* without modification, are permitted provided that the following
|
|
Packit |
13e616 |
* conditions are met:
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* - Redistributions of source code must retain the above
|
|
Packit |
13e616 |
* copyright notice, this list of conditions and the following
|
|
Packit |
13e616 |
* disclaimer.
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* - Redistributions in binary form must reproduce the above
|
|
Packit |
13e616 |
* copyright notice, this list of conditions and the following
|
|
Packit |
13e616 |
* disclaimer in the documentation and/or other materials
|
|
Packit |
13e616 |
* provided with the distribution.
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
Packit |
13e616 |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
Packit |
13e616 |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
Packit |
13e616 |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
Packit |
13e616 |
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
Packit |
13e616 |
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
Packit |
13e616 |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
Packit |
13e616 |
* SOFTWARE.
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Abstract:
|
|
Packit |
13e616 |
* Implementation of Up Down Algorithm using ranking & Min Hop
|
|
Packit |
13e616 |
* Calculation functions
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#if HAVE_CONFIG_H
|
|
Packit |
13e616 |
# include <config.h>
|
|
Packit |
13e616 |
#endif /* HAVE_CONFIG_H */
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#include <stdlib.h>
|
|
Packit |
13e616 |
#include <ctype.h>
|
|
Packit |
13e616 |
#include <complib/cl_debug.h>
|
|
Packit |
13e616 |
#include <complib/cl_qmap.h>
|
|
Packit |
13e616 |
#include <opensm/osm_file_ids.h>
|
|
Packit |
13e616 |
#define FILE_ID OSM_FILE_UCAST_UPDN_C
|
|
Packit |
13e616 |
#include <opensm/osm_switch.h>
|
|
Packit |
13e616 |
#include <opensm/osm_opensm.h>
|
|
Packit |
13e616 |
#include <opensm/osm_ucast_mgr.h>
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* //////////////////////////// */
|
|
Packit |
13e616 |
/* Local types */
|
|
Packit |
13e616 |
/* //////////////////////////// */
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* direction */
|
|
Packit |
13e616 |
typedef enum updn_switch_dir {
|
|
Packit |
13e616 |
UP = 0,
|
|
Packit |
13e616 |
DOWN
|
|
Packit |
13e616 |
} updn_switch_dir_t;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* updn structure */
|
|
Packit |
13e616 |
typedef struct updn {
|
|
Packit |
13e616 |
unsigned num_roots;
|
|
Packit |
13e616 |
osm_opensm_t *p_osm;
|
|
Packit |
13e616 |
} updn_t;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
struct updn_node {
|
|
Packit |
13e616 |
cl_list_item_t list;
|
|
Packit |
13e616 |
osm_switch_t *sw;
|
|
Packit |
13e616 |
uint64_t id;
|
|
Packit |
13e616 |
updn_switch_dir_t dir;
|
|
Packit |
13e616 |
unsigned rank;
|
|
Packit |
13e616 |
unsigned visited;
|
|
Packit |
13e616 |
};
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* This function returns direction based on rank and guid info of current &
|
|
Packit |
13e616 |
remote ports */
|
|
Packit |
13e616 |
static updn_switch_dir_t updn_get_dir(unsigned cur_rank, unsigned rem_rank,
|
|
Packit |
13e616 |
uint64_t cur_id, uint64_t rem_id)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
/* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect
|
|
Packit |
13e616 |
directly, but in case they are we assign to root node an UP direction to allow UPDN to discover
|
|
Packit |
13e616 |
the subnet correctly (and not from the point of view of the last root node).
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (!cur_rank && !rem_rank)
|
|
Packit |
13e616 |
return UP;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (cur_rank < rem_rank)
|
|
Packit |
13e616 |
return DOWN;
|
|
Packit |
13e616 |
else if (cur_rank > rem_rank)
|
|
Packit |
13e616 |
return UP;
|
|
Packit |
13e616 |
else {
|
|
Packit |
13e616 |
/* Equal rank, decide by id number, bigger == UP direction */
|
|
Packit |
13e616 |
if (cur_id > rem_id)
|
|
Packit |
13e616 |
return UP;
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
return DOWN;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/**********************************************************************
|
|
Packit |
13e616 |
* This function does the bfs of min hop table calculation by guid index
|
|
Packit |
13e616 |
* as a starting point.
|
|
Packit |
13e616 |
**********************************************************************/
|
|
Packit |
13e616 |
static int updn_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
|
|
Packit |
13e616 |
IN osm_switch_t * p_sw)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
uint8_t pn, pn_rem;
|
|
Packit |
13e616 |
cl_qlist_t list;
|
|
Packit |
13e616 |
uint16_t lid;
|
|
Packit |
13e616 |
struct updn_node *u;
|
|
Packit |
13e616 |
updn_switch_dir_t next_dir, current_dir;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
lid = osm_node_get_base_lid(p_sw->p_node, 0);
|
|
Packit |
13e616 |
lid = cl_ntoh16(lid);
|
|
Packit |
13e616 |
osm_switch_set_hops(p_sw, lid, 0, 0);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Starting from switch - port GUID 0x%" PRIx64 " lid %u\n",
|
|
Packit |
13e616 |
cl_ntoh64(p_sw->p_node->node_info.port_guid), lid);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
u = p_sw->priv;
|
|
Packit |
13e616 |
u->dir = UP;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Update list with the new element */
|
|
Packit |
13e616 |
cl_qlist_init(&list);
|
|
Packit |
13e616 |
cl_qlist_insert_tail(&list, &u->list);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* BFS the list till no next element */
|
|
Packit |
13e616 |
while (!cl_is_qlist_empty(&list)) {
|
|
Packit |
13e616 |
u = (struct updn_node *)cl_qlist_remove_head(&list);
|
|
Packit |
13e616 |
u->visited = 0; /* cleanup */
|
|
Packit |
13e616 |
current_dir = u->dir;
|
|
Packit |
13e616 |
/* Go over all ports of the switch and find unvisited remote nodes */
|
|
Packit |
13e616 |
for (pn = 1; pn < u->sw->num_ports; pn++) {
|
|
Packit |
13e616 |
osm_node_t *p_remote_node;
|
|
Packit |
13e616 |
struct updn_node *rem_u;
|
|
Packit |
13e616 |
uint8_t current_min_hop, remote_min_hop,
|
|
Packit |
13e616 |
set_hop_return_value;
|
|
Packit |
13e616 |
osm_switch_t *p_remote_sw;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_remote_node =
|
|
Packit |
13e616 |
osm_node_get_remote_node(u->sw->p_node, pn,
|
|
Packit |
13e616 |
&pn_rem);
|
|
Packit |
13e616 |
/* If no remote node OR remote node is not a SWITCH
|
|
Packit |
13e616 |
continue to next pn */
|
|
Packit |
13e616 |
if (!p_remote_node || !p_remote_node->sw)
|
|
Packit |
13e616 |
continue;
|
|
Packit |
13e616 |
/* Fetch remote guid only after validation of remote node */
|
|
Packit |
13e616 |
p_remote_sw = p_remote_node->sw;
|
|
Packit |
13e616 |
rem_u = p_remote_sw->priv;
|
|
Packit |
13e616 |
/* Decide which direction to mark it (UP/DOWN) */
|
|
Packit |
13e616 |
next_dir = updn_get_dir(u->rank, rem_u->rank,
|
|
Packit |
13e616 |
u->id, rem_u->id);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Check if this is a legal step : the only illegal step is going
|
|
Packit |
13e616 |
from DOWN to UP */
|
|
Packit |
13e616 |
if ((current_dir == DOWN) && (next_dir == UP)) {
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Avoiding move from 0x%016" PRIx64
|
|
Packit |
13e616 |
" to 0x%016" PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)),
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(p_remote_node)));
|
|
Packit |
13e616 |
/* Illegal step */
|
|
Packit |
13e616 |
continue;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
/* Set MinHop value for the current lid */
|
|
Packit |
13e616 |
current_min_hop = osm_switch_get_least_hops(u->sw, lid);
|
|
Packit |
13e616 |
/* Check hop count if better insert into list && update
|
|
Packit |
13e616 |
the remote node Min Hop Table */
|
|
Packit |
13e616 |
remote_min_hop =
|
|
Packit |
13e616 |
osm_switch_get_hop_count(p_remote_sw, lid, pn_rem);
|
|
Packit |
13e616 |
if (current_min_hop + 1 < remote_min_hop) {
|
|
Packit |
13e616 |
set_hop_return_value =
|
|
Packit |
13e616 |
osm_switch_set_hops(p_remote_sw, lid,
|
|
Packit |
13e616 |
pn_rem,
|
|
Packit |
13e616 |
current_min_hop + 1);
|
|
Packit |
13e616 |
if (set_hop_return_value) {
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AA01: "
|
|
Packit |
13e616 |
"Invalid value returned from set min hop is: %d\n",
|
|
Packit |
13e616 |
set_hop_return_value);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
/* Check if remote port has already been visited */
|
|
Packit |
13e616 |
if (!rem_u->visited) {
|
|
Packit |
13e616 |
/* Insert updn_switch item into the list */
|
|
Packit |
13e616 |
rem_u->dir = next_dir;
|
|
Packit |
13e616 |
rem_u->visited = 1;
|
|
Packit |
13e616 |
cl_qlist_insert_tail(&list,
|
|
Packit |
13e616 |
&rem_u->list);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(p_log);
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* NOTE : PLS check if we need to decide that the first */
|
|
Packit |
13e616 |
/* rank is a SWITCH for BFS purpose */
|
|
Packit |
13e616 |
static int updn_subn_rank(IN updn_t * p_updn)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_switch_t *p_sw;
|
|
Packit |
13e616 |
osm_physp_t *p_physp, *p_remote_physp;
|
|
Packit |
13e616 |
cl_qlist_t list;
|
|
Packit |
13e616 |
cl_map_item_t *item;
|
|
Packit |
13e616 |
struct updn_node *u, *remote_u;
|
|
Packit |
13e616 |
uint8_t num_ports, port_num;
|
|
Packit |
13e616 |
osm_log_t *p_log = &p_updn->p_osm->log;
|
|
Packit |
13e616 |
unsigned max_rank = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(p_log);
|
|
Packit |
13e616 |
cl_qlist_init(&list);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* add all roots to the list */
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
u = p_sw->priv;
|
|
Packit |
13e616 |
if (!u->rank)
|
|
Packit |
13e616 |
cl_qlist_insert_tail(&list, &u->list);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* BFS the list till it's empty */
|
|
Packit |
13e616 |
while (!cl_is_qlist_empty(&list)) {
|
|
Packit |
13e616 |
u = (struct updn_node *)cl_qlist_remove_head(&list);
|
|
Packit |
13e616 |
/* Go over all remote nodes and rank them (if not already visited) */
|
|
Packit |
13e616 |
p_sw = u->sw;
|
|
Packit |
13e616 |
num_ports = p_sw->num_ports;
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Handling switch GUID 0x%" PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
|
|
Packit |
13e616 |
for (port_num = 1; port_num < num_ports; port_num++) {
|
|
Packit |
13e616 |
ib_net64_t port_guid;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Current port fetched in order to get remote side */
|
|
Packit |
13e616 |
p_physp =
|
|
Packit |
13e616 |
osm_node_get_physp_ptr(p_sw->p_node, port_num);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (!p_physp)
|
|
Packit |
13e616 |
continue;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_remote_physp = p_physp->p_remote_physp;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
make sure that all the following occur on p_remote_physp:
|
|
Packit |
13e616 |
1. The port isn't NULL
|
|
Packit |
13e616 |
2. It is a switch
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (p_remote_physp && p_remote_physp->p_node->sw) {
|
|
Packit |
13e616 |
remote_u = p_remote_physp->p_node->sw->priv;
|
|
Packit |
13e616 |
port_guid = p_remote_physp->port_guid;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (remote_u->rank > u->rank + 1) {
|
|
Packit |
13e616 |
remote_u->rank = u->rank + 1;
|
|
Packit |
13e616 |
max_rank = remote_u->rank;
|
|
Packit |
13e616 |
cl_qlist_insert_tail(&list,
|
|
Packit |
13e616 |
&remote_u->list);
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Rank of port GUID 0x%" PRIx64
|
|
Packit |
13e616 |
" = %u\n", cl_ntoh64(port_guid),
|
|
Packit |
13e616 |
remote_u->rank);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Print Summary of ranking */
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Subnet ranking completed. Max Node Rank = %d\n", max_rank);
|
|
Packit |
13e616 |
OSM_LOG_EXIT(p_log);
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* hack: preserve min hops entries to any other root switches */
|
|
Packit |
13e616 |
static void updn_clear_non_root_hops(updn_t * updn, osm_switch_t * sw)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_port_t *port;
|
|
Packit |
13e616 |
unsigned i;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (i = 0; i < sw->num_hops; i++)
|
|
Packit |
13e616 |
if (sw->hops[i]) {
|
|
Packit |
13e616 |
port = osm_get_port_by_lid_ho(&updn->p_osm->subn, i);
|
|
Packit |
13e616 |
if (!port || !port->p_node->sw
|
|
Packit |
13e616 |
|| ((struct updn_node *)port->p_node->sw->priv)->
|
|
Packit |
13e616 |
rank != 0)
|
|
Packit |
13e616 |
memset(sw->hops[i], 0xff, sw->num_ports);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static int updn_set_min_hop_table(IN updn_t * p_updn)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_subn_t *p_subn = &p_updn->p_osm->subn;
|
|
Packit |
13e616 |
osm_log_t *p_log = &p_updn->p_osm->log;
|
|
Packit |
13e616 |
osm_switch_t *p_sw;
|
|
Packit |
13e616 |
cl_map_item_t *item;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Go over all the switches in the subnet - for each init their Min Hop
|
|
Packit |
13e616 |
Table */
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Init Min Hop Table of all switches [\n");
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
/* Clear Min Hop Table */
|
|
Packit |
13e616 |
if (p_subn->opt.connect_roots)
|
|
Packit |
13e616 |
updn_clear_non_root_hops(p_updn, p_sw);
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
osm_switch_clear_hops(p_sw);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Init Min Hop Table of all switches ]\n");
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Now do the BFS for each port in the subnet */
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"BFS through all port guids in the subnet [\n");
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
updn_bfs_by_node(p_log, p_subn, p_sw);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"BFS through all port guids in the subnet ]\n");
|
|
Packit |
13e616 |
/* Cleanup */
|
|
Packit |
13e616 |
OSM_LOG_EXIT(p_log);
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static int updn_build_lid_matrices(IN updn_t * p_updn)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
int status;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(&p_updn->p_osm->log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Ranking all port guids in the list\n");
|
|
Packit |
13e616 |
if (!p_updn->num_roots) {
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0A: "
|
|
Packit |
13e616 |
"No guids were provided or number of guids is 0\n");
|
|
Packit |
13e616 |
status = -1;
|
|
Packit |
13e616 |
goto _exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Check if it's not a switched subnet */
|
|
Packit |
13e616 |
if (cl_is_qmap_empty(&p_updn->p_osm->subn.sw_guid_tbl)) {
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0B: "
|
|
Packit |
13e616 |
"This is not a switched subnet, cannot perform UPDN algorithm\n");
|
|
Packit |
13e616 |
status = -1;
|
|
Packit |
13e616 |
goto _exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Rank the subnet switches */
|
|
Packit |
13e616 |
if (updn_subn_rank(p_updn)) {
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0E: "
|
|
Packit |
13e616 |
"Failed to assign ranks\n");
|
|
Packit |
13e616 |
status = -1;
|
|
Packit |
13e616 |
goto _exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* After multiple ranking need to set Min Hop Table by UpDn algorithm */
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Setting all switches' Min Hop Table\n");
|
|
Packit |
13e616 |
status = updn_set_min_hop_table(p_updn);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
_exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&p_updn->p_osm->log);
|
|
Packit |
13e616 |
return status;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static struct updn_node *create_updn_node(osm_switch_t * sw)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
struct updn_node *u;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
u = malloc(sizeof(*u));
|
|
Packit |
13e616 |
if (!u)
|
|
Packit |
13e616 |
return NULL;
|
|
Packit |
13e616 |
memset(u, 0, sizeof(*u));
|
|
Packit |
13e616 |
u->sw = sw;
|
|
Packit |
13e616 |
u->id = cl_ntoh64(osm_node_get_node_guid(sw->p_node));
|
|
Packit |
13e616 |
u->rank = 0xffffffff;
|
|
Packit |
13e616 |
return u;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void delete_updn_node(struct updn_node *u)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
u->sw->priv = NULL;
|
|
Packit |
13e616 |
free(u);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Find Root nodes automatically by Min Hop Table info */
|
|
Packit |
13e616 |
static void updn_find_root_nodes_by_min_hop(OUT updn_t * p_updn)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_opensm_t *p_osm = p_updn->p_osm;
|
|
Packit |
13e616 |
osm_switch_t *p_sw;
|
|
Packit |
13e616 |
osm_port_t *p_port;
|
|
Packit |
13e616 |
osm_physp_t *p_physp;
|
|
Packit |
13e616 |
cl_map_item_t *item;
|
|
Packit |
13e616 |
double thd1, thd2;
|
|
Packit |
13e616 |
unsigned i, cas_num = 0;
|
|
Packit |
13e616 |
unsigned *cas_per_sw;
|
|
Packit |
13e616 |
uint16_t lid_ho;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(&p_osm->log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Current number of ports in the subnet is %d\n",
|
|
Packit |
13e616 |
cl_qmap_count(&p_osm->subn.port_guid_tbl));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
lid_ho = (uint16_t) cl_ptr_vector_get_size(&p_updn->p_osm->subn.port_lid_tbl) + 1;
|
|
Packit |
13e616 |
cas_per_sw = malloc(lid_ho * sizeof(*cas_per_sw));
|
|
Packit |
13e616 |
if (!cas_per_sw) {
|
|
Packit |
13e616 |
OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR AA14: "
|
|
Packit |
13e616 |
"cannot alloc mem for CAs per switch counter array\n");
|
|
Packit |
13e616 |
goto _exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
memset(cas_per_sw, 0, lid_ho * sizeof(*cas_per_sw));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Find the Maximum number of CAs (and routers) for histogram normalization */
|
|
Packit |
13e616 |
OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Finding the number of CAs and storing them in cl_map\n");
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_updn->p_osm->subn.port_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_updn->p_osm->subn.port_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_port = (osm_port_t *)item;
|
|
Packit |
13e616 |
if (!p_port->p_node->sw) {
|
|
Packit |
13e616 |
p_physp = p_port->p_physp->p_remote_physp;
|
|
Packit |
13e616 |
if (!p_physp || !p_physp->p_node->sw)
|
|
Packit |
13e616 |
continue;
|
|
Packit |
13e616 |
lid_ho = osm_node_get_base_lid(p_physp->p_node, 0);
|
|
Packit |
13e616 |
lid_ho = cl_ntoh16(lid_ho);
|
|
Packit |
13e616 |
cas_per_sw[lid_ho]++;
|
|
Packit |
13e616 |
cas_num++;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
thd1 = cas_num * 0.9;
|
|
Packit |
13e616 |
thd2 = cas_num * 0.05;
|
|
Packit |
13e616 |
OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Found %u CAs and RTRs, %u SWs in the subnet. "
|
|
Packit |
13e616 |
"Thresholds are thd1 = %f && thd2 = %f\n",
|
|
Packit |
13e616 |
cas_num, cl_qmap_count(&p_osm->subn.sw_guid_tbl), thd1, thd2);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Passing through all switches to collect Min Hop info\n");
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
unsigned hop_hist[IB_SUBNET_PATH_HOPS_MAX];
|
|
Packit |
13e616 |
uint16_t max_lid_ho;
|
|
Packit |
13e616 |
uint8_t hop_val;
|
|
Packit |
13e616 |
uint16_t numHopBarsOverThd1 = 0;
|
|
Packit |
13e616 |
uint16_t numHopBarsOverThd2 = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *) item;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
memset(hop_hist, 0, sizeof(hop_hist));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
max_lid_ho = p_sw->max_lid_ho;
|
|
Packit |
13e616 |
for (lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++)
|
|
Packit |
13e616 |
if (cas_per_sw[lid_ho]) {
|
|
Packit |
13e616 |
hop_val =
|
|
Packit |
13e616 |
osm_switch_get_least_hops(p_sw, lid_ho);
|
|
Packit |
13e616 |
if (hop_val >= IB_SUBNET_PATH_HOPS_MAX)
|
|
Packit |
13e616 |
continue;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
hop_hist[hop_val] += cas_per_sw[lid_ho];
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Now recognize the spines by requiring one bar to be
|
|
Packit |
13e616 |
above 90% of the number of CAs and RTRs */
|
|
Packit |
13e616 |
for (i = 0; i < IB_SUBNET_PATH_HOPS_MAX; i++) {
|
|
Packit |
13e616 |
if (hop_hist[i] > thd1)
|
|
Packit |
13e616 |
numHopBarsOverThd1++;
|
|
Packit |
13e616 |
if (hop_hist[i] > thd2)
|
|
Packit |
13e616 |
numHopBarsOverThd2++;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* If thd conditions are valid - rank the root node */
|
|
Packit |
13e616 |
if (numHopBarsOverThd1 == 1 && numHopBarsOverThd2 == 1) {
|
|
Packit |
13e616 |
OSM_LOG(&p_osm->log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Ranking GUID 0x%" PRIx64 " as root node\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
|
|
Packit |
13e616 |
((struct updn_node *)p_sw->priv)->rank = 0;
|
|
Packit |
13e616 |
p_updn->num_roots++;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
free(cas_per_sw);
|
|
Packit |
13e616 |
_exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&p_osm->log);
|
|
Packit |
13e616 |
return;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void dump_roots(cl_map_item_t *item, FILE *file, void *cxt)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_switch_t *sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
if (!((struct updn_node *)sw->priv)->rank)
|
|
Packit |
13e616 |
fprintf(file, "0x%" PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(sw->p_node)));
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static int update_id(void *cxt, uint64_t guid, char *p)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_opensm_t *osm = cxt;
|
|
Packit |
13e616 |
osm_switch_t *sw;
|
|
Packit |
13e616 |
uint64_t id;
|
|
Packit |
13e616 |
char *e;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
sw = osm_get_switch_by_guid(&osm->subn, cl_hton64(guid));
|
|
Packit |
13e616 |
if (!sw) {
|
|
Packit |
13e616 |
OSM_LOG(&osm->log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"switch with guid 0x%" PRIx64 " is not found\n", guid);
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
id = strtoull(p, &e, 0);
|
|
Packit |
13e616 |
if (*e && !isspace(*e)) {
|
|
Packit |
13e616 |
OSM_LOG(&osm->log, OSM_LOG_ERROR,
|
|
Packit |
13e616 |
"ERR AA05: cannot parse node id \'%s\'", p);
|
|
Packit |
13e616 |
return -1;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(&osm->log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"update node 0x%" PRIx64 " id to 0x%" PRIx64 "\n", guid, id);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
((struct updn_node *)sw->priv)->id = id;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static int rank_root_node(void *cxt, uint64_t guid, char *p)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
updn_t *updn = cxt;
|
|
Packit |
13e616 |
osm_switch_t *sw;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
sw = osm_get_switch_by_guid(&updn->p_osm->subn, cl_hton64(guid));
|
|
Packit |
13e616 |
if (!sw) {
|
|
Packit |
13e616 |
OSM_LOG(&updn->p_osm->log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"switch with guid 0x%" PRIx64 " is not found\n", guid);
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(&updn->p_osm->log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Ranking root port GUID 0x%" PRIx64 "\n", guid);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
((struct updn_node *)sw->priv)->rank = 0;
|
|
Packit |
13e616 |
updn->num_roots++;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* UPDN callback function */
|
|
Packit |
13e616 |
static int updn_lid_matrices(void *ctx)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
updn_t *p_updn = ctx;
|
|
Packit |
13e616 |
cl_map_item_t *item;
|
|
Packit |
13e616 |
osm_switch_t *p_sw;
|
|
Packit |
13e616 |
int ret = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(&p_updn->p_osm->log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
p_sw->priv = create_updn_node(p_sw);
|
|
Packit |
13e616 |
if (!p_sw->priv) {
|
|
Packit |
13e616 |
OSM_LOG(&(p_updn->p_osm->log), OSM_LOG_ERROR, "ERR AA0C: "
|
|
Packit |
13e616 |
"cannot create updn node\n");
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&p_updn->p_osm->log);
|
|
Packit |
13e616 |
return -1;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* First setup root nodes */
|
|
Packit |
13e616 |
p_updn->num_roots = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_updn->p_osm->subn.opt.root_guid_file) {
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"UPDN - Fetching root nodes from file \'%s\'\n",
|
|
Packit |
13e616 |
p_updn->p_osm->subn.opt.root_guid_file);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
ret = parse_node_map(p_updn->p_osm->subn.opt.root_guid_file,
|
|
Packit |
13e616 |
rank_root_node, p_updn);
|
|
Packit |
13e616 |
if (ret) {
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA02: "
|
|
Packit |
13e616 |
"cannot parse root guids file \'%s\'\n",
|
|
Packit |
13e616 |
p_updn->p_osm->subn.opt.root_guid_file);
|
|
Packit |
13e616 |
osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
|
|
Packit |
13e616 |
updn_find_root_nodes_by_min_hop(p_updn);
|
|
Packit |
13e616 |
} else if (p_updn->p_osm->subn.opt.connect_roots &&
|
|
Packit |
13e616 |
p_updn->num_roots > 1)
|
|
Packit |
13e616 |
osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr);
|
|
Packit |
13e616 |
updn_find_root_nodes_by_min_hop(p_updn);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_updn->p_osm->subn.opt.ids_guid_file) {
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"UPDN - update node ids from file \'%s\'\n",
|
|
Packit |
13e616 |
p_updn->p_osm->subn.opt.ids_guid_file);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
ret = parse_node_map(p_updn->p_osm->subn.opt.ids_guid_file,
|
|
Packit |
13e616 |
update_id, p_updn->p_osm);
|
|
Packit |
13e616 |
if (ret)
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA03: "
|
|
Packit |
13e616 |
"cannot parse node ids file \'%s\'\n",
|
|
Packit |
13e616 |
p_updn->p_osm->subn.opt.ids_guid_file);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Only if there are assigned root nodes do the algorithm, otherwise perform do nothing */
|
|
Packit |
13e616 |
if (p_updn->num_roots) {
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"activating UPDN algorithm\n");
|
|
Packit |
13e616 |
ret = updn_build_lid_matrices(p_updn);
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
OSM_LOG(&p_updn->p_osm->log, OSM_LOG_INFO,
|
|
Packit |
13e616 |
"disabling UPDN algorithm, no root nodes were found\n");
|
|
Packit |
13e616 |
ret = -1;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (OSM_LOG_IS_ACTIVE_V2(&p_updn->p_osm->log, OSM_LOG_ROUTING))
|
|
Packit |
13e616 |
osm_dump_qmap_to_file(p_updn->p_osm, "opensm-updn-roots.dump",
|
|
Packit |
13e616 |
&p_updn->p_osm->subn.sw_guid_tbl,
|
|
Packit |
13e616 |
dump_roots, NULL);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *) item;
|
|
Packit |
13e616 |
delete_updn_node(p_sw->priv);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&p_updn->p_osm->log);
|
|
Packit |
13e616 |
return ret;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void updn_delete(void *context)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
free(context);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
int osm_ucast_updn_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
updn_t *updn;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
updn = malloc(sizeof(updn_t));
|
|
Packit |
13e616 |
if (!updn)
|
|
Packit |
13e616 |
return -1;
|
|
Packit |
13e616 |
memset(updn, 0, sizeof(updn_t));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
updn->p_osm = osm;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
r->context = updn;
|
|
Packit |
13e616 |
r->destroy = updn_delete;
|
|
Packit |
13e616 |
r->build_lid_matrices = updn_lid_matrices;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|