|
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 |
* Copyright (c) 2009 Battelle Memorial Institue. 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_DNUP_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 dnup_switch_dir {
|
|
Packit |
13e616 |
UP = 0,
|
|
Packit |
13e616 |
DOWN,
|
|
Packit |
13e616 |
EQUAL
|
|
Packit |
13e616 |
} dnup_switch_dir_t;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* dnup structure */
|
|
Packit |
13e616 |
typedef struct dnup {
|
|
Packit |
13e616 |
osm_opensm_t *p_osm;
|
|
Packit |
13e616 |
} dnup_t;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
struct dnup_node {
|
|
Packit |
13e616 |
cl_list_item_t list;
|
|
Packit |
13e616 |
osm_switch_t *sw;
|
|
Packit |
13e616 |
dnup_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 dnup_switch_dir_t dnup_get_dir(unsigned cur_rank, unsigned rem_rank)
|
|
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 DNUP 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 EQUAL;
|
|
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 |
return EQUAL;
|
|
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 dnup_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
|
|
Packit |
13e616 |
IN osm_switch_t * p_sw, IN uint8_t prune_weight,
|
|
Packit |
13e616 |
OUT uint8_t * max_hops)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
uint8_t pn, pn_rem;
|
|
Packit |
13e616 |
cl_qlist_t list;
|
|
Packit |
13e616 |
uint16_t lid;
|
|
Packit |
13e616 |
struct dnup_node *u;
|
|
Packit |
13e616 |
dnup_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 = DOWN;
|
|
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 dnup_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 dnup_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 = dnup_get_dir(u->rank, rem_u->rank);
|
|
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 |
|
|
Packit |
13e616 |
/* Check if this is a legal step : the only illegal step is going
|
|
Packit |
13e616 |
from UP to DOWN */
|
|
Packit |
13e616 |
if ((current_dir == UP) && (next_dir == DOWN)) {
|
|
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. If prune_weight is set, allow it with an
|
|
Packit |
13e616 |
* additional weight
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if(prune_weight) {
|
|
Packit |
13e616 |
current_min_hop+=prune_weight;
|
|
Packit |
13e616 |
if(current_min_hop >= 64) {
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_ERROR,
|
|
Packit |
13e616 |
"ERR AE02: Too many hops on subnet,"
|
|
Packit |
13e616 |
" can't relax illegal Dn/Up transition.");
|
|
Packit |
13e616 |
osm_switch_set_hops(p_remote_sw, lid,
|
|
Packit |
13e616 |
pn_rem, OSM_NO_PATH);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
continue;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
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(max_hops && current_min_hop + 1 > *max_hops) {
|
|
Packit |
13e616 |
*max_hops = current_min_hop + 1;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (set_hop_return_value) {
|
|
Packit |
13e616 |
OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AE01: "
|
|
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 dnup_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 dnup_subn_rank(IN dnup_t * p_dnup)
|
|
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 dnup_node *u, *remote_u;
|
|
Packit |
13e616 |
uint8_t num_ports, port_num;
|
|
Packit |
13e616 |
osm_log_t *p_log = &p_dnup->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 node level switches to the list */
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_dnup->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 == 0)
|
|
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 dnup_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 |
static int dnup_set_min_hop_table(IN dnup_t * p_dnup)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_subn_t *p_subn = &p_dnup->p_osm->subn;
|
|
Packit |
13e616 |
osm_log_t *p_log = &p_dnup->p_osm->log;
|
|
Packit |
13e616 |
osm_switch_t *p_sw;
|
|
Packit |
13e616 |
struct dnup_node *u;
|
|
Packit |
13e616 |
cl_map_item_t *item;
|
|
Packit |
13e616 |
uint8_t max_hops = 0;
|
|
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_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_dnup->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 |
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_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
dnup_bfs_by_node(p_log, p_subn, p_sw, 0, &max_hops);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if(p_subn->opt.connect_roots) {
|
|
Packit |
13e616 |
/*This is probably not necessary, by I am more comfortable
|
|
Packit |
13e616 |
* clearing any possible side effects from the previous
|
|
Packit |
13e616 |
* dnup routing pass
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
osm_switch_clear_hops(p_sw);
|
|
Packit |
13e616 |
u = (struct dnup_node *) p_sw->priv;
|
|
Packit |
13e616 |
u->visited = 0;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
dnup_bfs_by_node(p_log, p_subn, p_sw, max_hops + 1, NULL);
|
|
Packit |
13e616 |
}
|
|
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 dnup_build_lid_matrices(IN dnup_t * p_dnup)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
int status;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(&p_dnup->p_osm->log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Ranking all port guids in the list\n");
|
|
Packit |
13e616 |
/* Check if it's not a switched subnet */
|
|
Packit |
13e616 |
if (cl_is_qmap_empty(&p_dnup->p_osm->subn.sw_guid_tbl)) {
|
|
Packit |
13e616 |
OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_ERROR, "ERR AEOB: "
|
|
Packit |
13e616 |
"This is not a switched subnet, cannot perform DNUP algorithm\n");
|
|
Packit |
13e616 |
status = -1;
|
|
Packit |
13e616 |
goto _exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Rank the subnet switches */
|
|
Packit |
13e616 |
dnup_subn_rank(p_dnup);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* After multiple ranking need to set Min Hop Table by DnUp algorithm */
|
|
Packit |
13e616 |
OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Setting all switches' Min Hop Table\n");
|
|
Packit |
13e616 |
status = dnup_set_min_hop_table(p_dnup);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
_exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&p_dnup->p_osm->log);
|
|
Packit |
13e616 |
return status;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static struct dnup_node *create_dnup_node(osm_switch_t * sw)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
struct dnup_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->rank = 0xffffffff;
|
|
Packit |
13e616 |
return u;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void delete_dnup_node(struct dnup_node *u)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
u->sw->priv = NULL;
|
|
Packit |
13e616 |
free(u);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* DNUP callback function */
|
|
Packit |
13e616 |
static int dnup_lid_matrices(void *ctx)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
dnup_t *p_dnup = ctx;
|
|
Packit |
13e616 |
cl_map_item_t *item;
|
|
Packit |
13e616 |
osm_switch_t *p_sw;
|
|
Packit |
13e616 |
int ret = 0;
|
|
Packit |
13e616 |
int num_leafs = 0;
|
|
Packit |
13e616 |
uint8_t pn, pn_rem;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(&p_dnup->p_osm->log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_dnup->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_dnup_node(p_sw);
|
|
Packit |
13e616 |
if (!p_sw->priv) {
|
|
Packit |
13e616 |
OSM_LOG(&(p_dnup->p_osm->log), OSM_LOG_ERROR, "ERR AE0C: "
|
|
Packit |
13e616 |
"cannot create dnup node\n");
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&p_dnup->p_osm->log);
|
|
Packit |
13e616 |
return -1;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* First setup node level nodes */
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *)item;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (pn = 0; pn < p_sw->num_ports; pn++) {
|
|
Packit |
13e616 |
osm_node_t *p_remote_node;
|
|
Packit |
13e616 |
p_remote_node = osm_node_get_remote_node(p_sw->p_node, pn, &pn_rem);
|
|
Packit |
13e616 |
if(p_remote_node && !p_remote_node->sw) {
|
|
Packit |
13e616 |
struct dnup_node *u = p_sw->priv;
|
|
Packit |
13e616 |
u->rank = 0;
|
|
Packit |
13e616 |
OSM_LOG(&(p_dnup->p_osm->log),
|
|
Packit |
13e616 |
OSM_LOG_VERBOSE, "(%s) rank 0 leaf switch\n",
|
|
Packit |
13e616 |
p_sw->p_node->print_desc);
|
|
Packit |
13e616 |
num_leafs++;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if(num_leafs == 0) {
|
|
Packit |
13e616 |
OSM_LOG(&(p_dnup->p_osm->log),
|
|
Packit |
13e616 |
OSM_LOG_ERROR, "ERR AE0D: No leaf switches found, DnUp routing failed\n");
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&p_dnup->p_osm->log);
|
|
Packit |
13e616 |
return -1;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
ret = dnup_build_lid_matrices(p_dnup);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
|
|
Packit |
13e616 |
item = cl_qmap_next(item)) {
|
|
Packit |
13e616 |
p_sw = (osm_switch_t *) item;
|
|
Packit |
13e616 |
delete_dnup_node(p_sw->priv);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&p_dnup->p_osm->log);
|
|
Packit |
13e616 |
return ret;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void dnup_delete(void *context)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
free(context);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
int osm_ucast_dnup_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
dnup_t *dnup;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(&osm->log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
dnup = malloc(sizeof(dnup_t));
|
|
Packit |
13e616 |
if (!dnup)
|
|
Packit |
13e616 |
return -1;
|
|
Packit |
13e616 |
memset(dnup, 0, sizeof(dnup_t));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
dnup->p_osm = osm;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
r->context = dnup;
|
|
Packit |
13e616 |
r->destroy = dnup_delete;
|
|
Packit |
13e616 |
r->build_lid_matrices = dnup_lid_matrices;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(&osm->log);
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
}
|