1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3*d6b92ffaSHans Petter Selasky * Copyright (c) 2002-2007,2009 Mellanox Technologies LTD. All rights reserved.
4*d6b92ffaSHans Petter Selasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5*d6b92ffaSHans Petter Selasky * Copyright (c) 2009 HNR Consulting. All rights reserved.
6*d6b92ffaSHans Petter Selasky * Copyright (c) 2009 Battelle Memorial Institue. All rights reserved.
7*d6b92ffaSHans Petter Selasky *
8*d6b92ffaSHans Petter Selasky * This software is available to you under a choice of one of two
9*d6b92ffaSHans Petter Selasky * licenses. You may choose to be licensed under the terms of the GNU
10*d6b92ffaSHans Petter Selasky * General Public License (GPL) Version 2, available from the file
11*d6b92ffaSHans Petter Selasky * COPYING in the main directory of this source tree, or the
12*d6b92ffaSHans Petter Selasky * OpenIB.org BSD license below:
13*d6b92ffaSHans Petter Selasky *
14*d6b92ffaSHans Petter Selasky * Redistribution and use in source and binary forms, with or
15*d6b92ffaSHans Petter Selasky * without modification, are permitted provided that the following
16*d6b92ffaSHans Petter Selasky * conditions are met:
17*d6b92ffaSHans Petter Selasky *
18*d6b92ffaSHans Petter Selasky * - Redistributions of source code must retain the above
19*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
20*d6b92ffaSHans Petter Selasky * disclaimer.
21*d6b92ffaSHans Petter Selasky *
22*d6b92ffaSHans Petter Selasky * - Redistributions in binary form must reproduce the above
23*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
24*d6b92ffaSHans Petter Selasky * disclaimer in the documentation and/or other materials
25*d6b92ffaSHans Petter Selasky * provided with the distribution.
26*d6b92ffaSHans Petter Selasky *
27*d6b92ffaSHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28*d6b92ffaSHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29*d6b92ffaSHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30*d6b92ffaSHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31*d6b92ffaSHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32*d6b92ffaSHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33*d6b92ffaSHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34*d6b92ffaSHans Petter Selasky * SOFTWARE.
35*d6b92ffaSHans Petter Selasky *
36*d6b92ffaSHans Petter Selasky */
37*d6b92ffaSHans Petter Selasky
38*d6b92ffaSHans Petter Selasky /*
39*d6b92ffaSHans Petter Selasky * Abstract:
40*d6b92ffaSHans Petter Selasky * Implementation of Up Down Algorithm using ranking & Min Hop
41*d6b92ffaSHans Petter Selasky * Calculation functions
42*d6b92ffaSHans Petter Selasky */
43*d6b92ffaSHans Petter Selasky
44*d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
45*d6b92ffaSHans Petter Selasky # include <config.h>
46*d6b92ffaSHans Petter Selasky #endif /* HAVE_CONFIG_H */
47*d6b92ffaSHans Petter Selasky
48*d6b92ffaSHans Petter Selasky #include <stdlib.h>
49*d6b92ffaSHans Petter Selasky #include <ctype.h>
50*d6b92ffaSHans Petter Selasky #include <complib/cl_debug.h>
51*d6b92ffaSHans Petter Selasky #include <complib/cl_qmap.h>
52*d6b92ffaSHans Petter Selasky #include <opensm/osm_file_ids.h>
53*d6b92ffaSHans Petter Selasky #define FILE_ID OSM_FILE_UCAST_DNUP_C
54*d6b92ffaSHans Petter Selasky #include <opensm/osm_switch.h>
55*d6b92ffaSHans Petter Selasky #include <opensm/osm_opensm.h>
56*d6b92ffaSHans Petter Selasky #include <opensm/osm_ucast_mgr.h>
57*d6b92ffaSHans Petter Selasky
58*d6b92ffaSHans Petter Selasky /* //////////////////////////// */
59*d6b92ffaSHans Petter Selasky /* Local types */
60*d6b92ffaSHans Petter Selasky /* //////////////////////////// */
61*d6b92ffaSHans Petter Selasky
62*d6b92ffaSHans Petter Selasky /* direction */
63*d6b92ffaSHans Petter Selasky typedef enum dnup_switch_dir {
64*d6b92ffaSHans Petter Selasky UP = 0,
65*d6b92ffaSHans Petter Selasky DOWN,
66*d6b92ffaSHans Petter Selasky EQUAL
67*d6b92ffaSHans Petter Selasky } dnup_switch_dir_t;
68*d6b92ffaSHans Petter Selasky
69*d6b92ffaSHans Petter Selasky /* dnup structure */
70*d6b92ffaSHans Petter Selasky typedef struct dnup {
71*d6b92ffaSHans Petter Selasky osm_opensm_t *p_osm;
72*d6b92ffaSHans Petter Selasky } dnup_t;
73*d6b92ffaSHans Petter Selasky
74*d6b92ffaSHans Petter Selasky struct dnup_node {
75*d6b92ffaSHans Petter Selasky cl_list_item_t list;
76*d6b92ffaSHans Petter Selasky osm_switch_t *sw;
77*d6b92ffaSHans Petter Selasky dnup_switch_dir_t dir;
78*d6b92ffaSHans Petter Selasky unsigned rank;
79*d6b92ffaSHans Petter Selasky unsigned visited;
80*d6b92ffaSHans Petter Selasky };
81*d6b92ffaSHans Petter Selasky
82*d6b92ffaSHans Petter Selasky /* This function returns direction based on rank and guid info of current &
83*d6b92ffaSHans Petter Selasky remote ports */
dnup_get_dir(unsigned cur_rank,unsigned rem_rank)84*d6b92ffaSHans Petter Selasky static dnup_switch_dir_t dnup_get_dir(unsigned cur_rank, unsigned rem_rank)
85*d6b92ffaSHans Petter Selasky {
86*d6b92ffaSHans Petter Selasky /* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect
87*d6b92ffaSHans Petter Selasky directly, but in case they are we assign to root node an UP direction to allow DNUP to discover
88*d6b92ffaSHans Petter Selasky the subnet correctly (and not from the point of view of the last root node).
89*d6b92ffaSHans Petter Selasky */
90*d6b92ffaSHans Petter Selasky if (!cur_rank && !rem_rank)
91*d6b92ffaSHans Petter Selasky return EQUAL;
92*d6b92ffaSHans Petter Selasky
93*d6b92ffaSHans Petter Selasky if (cur_rank < rem_rank)
94*d6b92ffaSHans Petter Selasky return DOWN;
95*d6b92ffaSHans Petter Selasky else if (cur_rank > rem_rank)
96*d6b92ffaSHans Petter Selasky return UP;
97*d6b92ffaSHans Petter Selasky else
98*d6b92ffaSHans Petter Selasky return EQUAL;
99*d6b92ffaSHans Petter Selasky }
100*d6b92ffaSHans Petter Selasky
101*d6b92ffaSHans Petter Selasky /**********************************************************************
102*d6b92ffaSHans Petter Selasky * This function does the bfs of min hop table calculation by guid index
103*d6b92ffaSHans Petter Selasky * as a starting point.
104*d6b92ffaSHans Petter Selasky **********************************************************************/
dnup_bfs_by_node(IN osm_log_t * p_log,IN osm_subn_t * p_subn,IN osm_switch_t * p_sw,IN uint8_t prune_weight,OUT uint8_t * max_hops)105*d6b92ffaSHans Petter Selasky static int dnup_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
106*d6b92ffaSHans Petter Selasky IN osm_switch_t * p_sw, IN uint8_t prune_weight,
107*d6b92ffaSHans Petter Selasky OUT uint8_t * max_hops)
108*d6b92ffaSHans Petter Selasky {
109*d6b92ffaSHans Petter Selasky uint8_t pn, pn_rem;
110*d6b92ffaSHans Petter Selasky cl_qlist_t list;
111*d6b92ffaSHans Petter Selasky uint16_t lid;
112*d6b92ffaSHans Petter Selasky struct dnup_node *u;
113*d6b92ffaSHans Petter Selasky dnup_switch_dir_t next_dir, current_dir;
114*d6b92ffaSHans Petter Selasky
115*d6b92ffaSHans Petter Selasky OSM_LOG_ENTER(p_log);
116*d6b92ffaSHans Petter Selasky
117*d6b92ffaSHans Petter Selasky lid = osm_node_get_base_lid(p_sw->p_node, 0);
118*d6b92ffaSHans Petter Selasky lid = cl_ntoh16(lid);
119*d6b92ffaSHans Petter Selasky osm_switch_set_hops(p_sw, lid, 0, 0);
120*d6b92ffaSHans Petter Selasky
121*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_DEBUG,
122*d6b92ffaSHans Petter Selasky "Starting from switch - port GUID 0x%" PRIx64 " lid %u\n",
123*d6b92ffaSHans Petter Selasky cl_ntoh64(p_sw->p_node->node_info.port_guid), lid);
124*d6b92ffaSHans Petter Selasky
125*d6b92ffaSHans Petter Selasky u = p_sw->priv;
126*d6b92ffaSHans Petter Selasky u->dir = DOWN;
127*d6b92ffaSHans Petter Selasky
128*d6b92ffaSHans Petter Selasky /* Update list with the new element */
129*d6b92ffaSHans Petter Selasky cl_qlist_init(&list);
130*d6b92ffaSHans Petter Selasky cl_qlist_insert_tail(&list, &u->list);
131*d6b92ffaSHans Petter Selasky
132*d6b92ffaSHans Petter Selasky /* BFS the list till no next element */
133*d6b92ffaSHans Petter Selasky while (!cl_is_qlist_empty(&list)) {
134*d6b92ffaSHans Petter Selasky u = (struct dnup_node *)cl_qlist_remove_head(&list);
135*d6b92ffaSHans Petter Selasky u->visited = 0; /* cleanup */
136*d6b92ffaSHans Petter Selasky current_dir = u->dir;
137*d6b92ffaSHans Petter Selasky /* Go over all ports of the switch and find unvisited remote nodes */
138*d6b92ffaSHans Petter Selasky for (pn = 1; pn < u->sw->num_ports; pn++) {
139*d6b92ffaSHans Petter Selasky osm_node_t *p_remote_node;
140*d6b92ffaSHans Petter Selasky struct dnup_node *rem_u;
141*d6b92ffaSHans Petter Selasky uint8_t current_min_hop, remote_min_hop,
142*d6b92ffaSHans Petter Selasky set_hop_return_value;
143*d6b92ffaSHans Petter Selasky osm_switch_t *p_remote_sw;
144*d6b92ffaSHans Petter Selasky
145*d6b92ffaSHans Petter Selasky p_remote_node =
146*d6b92ffaSHans Petter Selasky osm_node_get_remote_node(u->sw->p_node, pn,
147*d6b92ffaSHans Petter Selasky &pn_rem);
148*d6b92ffaSHans Petter Selasky /* If no remote node OR remote node is not a SWITCH
149*d6b92ffaSHans Petter Selasky continue to next pn */
150*d6b92ffaSHans Petter Selasky if (!p_remote_node || !p_remote_node->sw)
151*d6b92ffaSHans Petter Selasky continue;
152*d6b92ffaSHans Petter Selasky /* Fetch remote guid only after validation of remote node */
153*d6b92ffaSHans Petter Selasky p_remote_sw = p_remote_node->sw;
154*d6b92ffaSHans Petter Selasky rem_u = p_remote_sw->priv;
155*d6b92ffaSHans Petter Selasky /* Decide which direction to mark it (UP/DOWN) */
156*d6b92ffaSHans Petter Selasky next_dir = dnup_get_dir(u->rank, rem_u->rank);
157*d6b92ffaSHans Petter Selasky
158*d6b92ffaSHans Petter Selasky /* Set MinHop value for the current lid */
159*d6b92ffaSHans Petter Selasky current_min_hop = osm_switch_get_least_hops(u->sw, lid);
160*d6b92ffaSHans Petter Selasky /* Check hop count if better insert into list && update
161*d6b92ffaSHans Petter Selasky the remote node Min Hop Table */
162*d6b92ffaSHans Petter Selasky remote_min_hop =
163*d6b92ffaSHans Petter Selasky osm_switch_get_hop_count(p_remote_sw, lid, pn_rem);
164*d6b92ffaSHans Petter Selasky
165*d6b92ffaSHans Petter Selasky /* Check if this is a legal step : the only illegal step is going
166*d6b92ffaSHans Petter Selasky from UP to DOWN */
167*d6b92ffaSHans Petter Selasky if ((current_dir == UP) && (next_dir == DOWN)) {
168*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_DEBUG,
169*d6b92ffaSHans Petter Selasky "Avoiding move from 0x%016" PRIx64
170*d6b92ffaSHans Petter Selasky " to 0x%016" PRIx64 "\n",
171*d6b92ffaSHans Petter Selasky cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)),
172*d6b92ffaSHans Petter Selasky cl_ntoh64(osm_node_get_node_guid(p_remote_node)));
173*d6b92ffaSHans Petter Selasky /* Illegal step. If prune_weight is set, allow it with an
174*d6b92ffaSHans Petter Selasky * additional weight
175*d6b92ffaSHans Petter Selasky */
176*d6b92ffaSHans Petter Selasky if(prune_weight) {
177*d6b92ffaSHans Petter Selasky current_min_hop+=prune_weight;
178*d6b92ffaSHans Petter Selasky if(current_min_hop >= 64) {
179*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_ERROR,
180*d6b92ffaSHans Petter Selasky "ERR AE02: Too many hops on subnet,"
181*d6b92ffaSHans Petter Selasky " can't relax illegal Dn/Up transition.");
182*d6b92ffaSHans Petter Selasky osm_switch_set_hops(p_remote_sw, lid,
183*d6b92ffaSHans Petter Selasky pn_rem, OSM_NO_PATH);
184*d6b92ffaSHans Petter Selasky }
185*d6b92ffaSHans Petter Selasky } else {
186*d6b92ffaSHans Petter Selasky continue;
187*d6b92ffaSHans Petter Selasky }
188*d6b92ffaSHans Petter Selasky }
189*d6b92ffaSHans Petter Selasky if (current_min_hop + 1 < remote_min_hop) {
190*d6b92ffaSHans Petter Selasky set_hop_return_value =
191*d6b92ffaSHans Petter Selasky osm_switch_set_hops(p_remote_sw, lid,
192*d6b92ffaSHans Petter Selasky pn_rem,
193*d6b92ffaSHans Petter Selasky current_min_hop + 1);
194*d6b92ffaSHans Petter Selasky if(max_hops && current_min_hop + 1 > *max_hops) {
195*d6b92ffaSHans Petter Selasky *max_hops = current_min_hop + 1;
196*d6b92ffaSHans Petter Selasky }
197*d6b92ffaSHans Petter Selasky if (set_hop_return_value) {
198*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AE01: "
199*d6b92ffaSHans Petter Selasky "Invalid value returned from set min hop is: %d\n",
200*d6b92ffaSHans Petter Selasky set_hop_return_value);
201*d6b92ffaSHans Petter Selasky }
202*d6b92ffaSHans Petter Selasky /* Check if remote port has already been visited */
203*d6b92ffaSHans Petter Selasky if (!rem_u->visited) {
204*d6b92ffaSHans Petter Selasky /* Insert dnup_switch item into the list */
205*d6b92ffaSHans Petter Selasky rem_u->dir = next_dir;
206*d6b92ffaSHans Petter Selasky rem_u->visited = 1;
207*d6b92ffaSHans Petter Selasky cl_qlist_insert_tail(&list,
208*d6b92ffaSHans Petter Selasky &rem_u->list);
209*d6b92ffaSHans Petter Selasky }
210*d6b92ffaSHans Petter Selasky }
211*d6b92ffaSHans Petter Selasky }
212*d6b92ffaSHans Petter Selasky }
213*d6b92ffaSHans Petter Selasky
214*d6b92ffaSHans Petter Selasky OSM_LOG_EXIT(p_log);
215*d6b92ffaSHans Petter Selasky return 0;
216*d6b92ffaSHans Petter Selasky }
217*d6b92ffaSHans Petter Selasky
218*d6b92ffaSHans Petter Selasky /* NOTE : PLS check if we need to decide that the first */
219*d6b92ffaSHans Petter Selasky /* rank is a SWITCH for BFS purpose */
dnup_subn_rank(IN dnup_t * p_dnup)220*d6b92ffaSHans Petter Selasky static int dnup_subn_rank(IN dnup_t * p_dnup)
221*d6b92ffaSHans Petter Selasky {
222*d6b92ffaSHans Petter Selasky osm_switch_t *p_sw;
223*d6b92ffaSHans Petter Selasky osm_physp_t *p_physp, *p_remote_physp;
224*d6b92ffaSHans Petter Selasky cl_qlist_t list;
225*d6b92ffaSHans Petter Selasky cl_map_item_t *item;
226*d6b92ffaSHans Petter Selasky struct dnup_node *u, *remote_u;
227*d6b92ffaSHans Petter Selasky uint8_t num_ports, port_num;
228*d6b92ffaSHans Petter Selasky osm_log_t *p_log = &p_dnup->p_osm->log;
229*d6b92ffaSHans Petter Selasky unsigned max_rank = 0;
230*d6b92ffaSHans Petter Selasky
231*d6b92ffaSHans Petter Selasky OSM_LOG_ENTER(p_log);
232*d6b92ffaSHans Petter Selasky cl_qlist_init(&list);
233*d6b92ffaSHans Petter Selasky
234*d6b92ffaSHans Petter Selasky /* add all node level switches to the list */
235*d6b92ffaSHans Petter Selasky for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
236*d6b92ffaSHans Petter Selasky item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
237*d6b92ffaSHans Petter Selasky item = cl_qmap_next(item)) {
238*d6b92ffaSHans Petter Selasky p_sw = (osm_switch_t *)item;
239*d6b92ffaSHans Petter Selasky u = p_sw->priv;
240*d6b92ffaSHans Petter Selasky if (u->rank == 0)
241*d6b92ffaSHans Petter Selasky cl_qlist_insert_tail(&list, &u->list);
242*d6b92ffaSHans Petter Selasky }
243*d6b92ffaSHans Petter Selasky
244*d6b92ffaSHans Petter Selasky /* BFS the list till it's empty */
245*d6b92ffaSHans Petter Selasky while (!cl_is_qlist_empty(&list)) {
246*d6b92ffaSHans Petter Selasky u = (struct dnup_node *)cl_qlist_remove_head(&list);
247*d6b92ffaSHans Petter Selasky /* Go over all remote nodes and rank them (if not already visited) */
248*d6b92ffaSHans Petter Selasky p_sw = u->sw;
249*d6b92ffaSHans Petter Selasky num_ports = p_sw->num_ports;
250*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_DEBUG,
251*d6b92ffaSHans Petter Selasky "Handling switch GUID 0x%" PRIx64 "\n",
252*d6b92ffaSHans Petter Selasky cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)));
253*d6b92ffaSHans Petter Selasky for (port_num = 1; port_num < num_ports; port_num++) {
254*d6b92ffaSHans Petter Selasky ib_net64_t port_guid;
255*d6b92ffaSHans Petter Selasky
256*d6b92ffaSHans Petter Selasky /* Current port fetched in order to get remote side */
257*d6b92ffaSHans Petter Selasky p_physp =
258*d6b92ffaSHans Petter Selasky osm_node_get_physp_ptr(p_sw->p_node, port_num);
259*d6b92ffaSHans Petter Selasky
260*d6b92ffaSHans Petter Selasky if (!p_physp)
261*d6b92ffaSHans Petter Selasky continue;
262*d6b92ffaSHans Petter Selasky
263*d6b92ffaSHans Petter Selasky p_remote_physp = p_physp->p_remote_physp;
264*d6b92ffaSHans Petter Selasky
265*d6b92ffaSHans Petter Selasky /*
266*d6b92ffaSHans Petter Selasky make sure that all the following occur on p_remote_physp:
267*d6b92ffaSHans Petter Selasky 1. The port isn't NULL
268*d6b92ffaSHans Petter Selasky 2. It is a switch
269*d6b92ffaSHans Petter Selasky */
270*d6b92ffaSHans Petter Selasky if (p_remote_physp && p_remote_physp->p_node->sw) {
271*d6b92ffaSHans Petter Selasky remote_u = p_remote_physp->p_node->sw->priv;
272*d6b92ffaSHans Petter Selasky port_guid = p_remote_physp->port_guid;
273*d6b92ffaSHans Petter Selasky
274*d6b92ffaSHans Petter Selasky if (remote_u->rank > u->rank + 1) {
275*d6b92ffaSHans Petter Selasky remote_u->rank = u->rank + 1;
276*d6b92ffaSHans Petter Selasky max_rank = remote_u->rank;
277*d6b92ffaSHans Petter Selasky cl_qlist_insert_tail(&list,
278*d6b92ffaSHans Petter Selasky &remote_u->list);
279*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_DEBUG,
280*d6b92ffaSHans Petter Selasky "Rank of port GUID 0x%" PRIx64
281*d6b92ffaSHans Petter Selasky " = %u\n", cl_ntoh64(port_guid),
282*d6b92ffaSHans Petter Selasky remote_u->rank);
283*d6b92ffaSHans Petter Selasky }
284*d6b92ffaSHans Petter Selasky }
285*d6b92ffaSHans Petter Selasky }
286*d6b92ffaSHans Petter Selasky }
287*d6b92ffaSHans Petter Selasky
288*d6b92ffaSHans Petter Selasky /* Print Summary of ranking */
289*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_VERBOSE,
290*d6b92ffaSHans Petter Selasky "Subnet ranking completed. Max Node Rank = %d\n", max_rank);
291*d6b92ffaSHans Petter Selasky OSM_LOG_EXIT(p_log);
292*d6b92ffaSHans Petter Selasky return 0;
293*d6b92ffaSHans Petter Selasky }
294*d6b92ffaSHans Petter Selasky
dnup_set_min_hop_table(IN dnup_t * p_dnup)295*d6b92ffaSHans Petter Selasky static int dnup_set_min_hop_table(IN dnup_t * p_dnup)
296*d6b92ffaSHans Petter Selasky {
297*d6b92ffaSHans Petter Selasky osm_subn_t *p_subn = &p_dnup->p_osm->subn;
298*d6b92ffaSHans Petter Selasky osm_log_t *p_log = &p_dnup->p_osm->log;
299*d6b92ffaSHans Petter Selasky osm_switch_t *p_sw;
300*d6b92ffaSHans Petter Selasky struct dnup_node *u;
301*d6b92ffaSHans Petter Selasky cl_map_item_t *item;
302*d6b92ffaSHans Petter Selasky uint8_t max_hops = 0;
303*d6b92ffaSHans Petter Selasky
304*d6b92ffaSHans Petter Selasky OSM_LOG_ENTER(p_log);
305*d6b92ffaSHans Petter Selasky
306*d6b92ffaSHans Petter Selasky /* Go over all the switches in the subnet - for each init their Min Hop
307*d6b92ffaSHans Petter Selasky Table */
308*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_VERBOSE,
309*d6b92ffaSHans Petter Selasky "Init Min Hop Table of all switches [\n");
310*d6b92ffaSHans Petter Selasky
311*d6b92ffaSHans Petter Selasky for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
312*d6b92ffaSHans Petter Selasky item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
313*d6b92ffaSHans Petter Selasky item = cl_qmap_next(item)) {
314*d6b92ffaSHans Petter Selasky p_sw = (osm_switch_t *)item;
315*d6b92ffaSHans Petter Selasky /* Clear Min Hop Table */
316*d6b92ffaSHans Petter Selasky osm_switch_clear_hops(p_sw);
317*d6b92ffaSHans Petter Selasky }
318*d6b92ffaSHans Petter Selasky
319*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_VERBOSE,
320*d6b92ffaSHans Petter Selasky "Init Min Hop Table of all switches ]\n");
321*d6b92ffaSHans Petter Selasky
322*d6b92ffaSHans Petter Selasky /* Now do the BFS for each port in the subnet */
323*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_VERBOSE,
324*d6b92ffaSHans Petter Selasky "BFS through all port guids in the subnet [\n");
325*d6b92ffaSHans Petter Selasky
326*d6b92ffaSHans Petter Selasky for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
327*d6b92ffaSHans Petter Selasky item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
328*d6b92ffaSHans Petter Selasky item = cl_qmap_next(item)) {
329*d6b92ffaSHans Petter Selasky p_sw = (osm_switch_t *)item;
330*d6b92ffaSHans Petter Selasky dnup_bfs_by_node(p_log, p_subn, p_sw, 0, &max_hops);
331*d6b92ffaSHans Petter Selasky }
332*d6b92ffaSHans Petter Selasky if(p_subn->opt.connect_roots) {
333*d6b92ffaSHans Petter Selasky /*This is probably not necessary, by I am more comfortable
334*d6b92ffaSHans Petter Selasky * clearing any possible side effects from the previous
335*d6b92ffaSHans Petter Selasky * dnup routing pass
336*d6b92ffaSHans Petter Selasky */
337*d6b92ffaSHans Petter Selasky for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
338*d6b92ffaSHans Petter Selasky item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
339*d6b92ffaSHans Petter Selasky item = cl_qmap_next(item)) {
340*d6b92ffaSHans Petter Selasky p_sw = (osm_switch_t *)item;
341*d6b92ffaSHans Petter Selasky osm_switch_clear_hops(p_sw);
342*d6b92ffaSHans Petter Selasky u = (struct dnup_node *) p_sw->priv;
343*d6b92ffaSHans Petter Selasky u->visited = 0;
344*d6b92ffaSHans Petter Selasky }
345*d6b92ffaSHans Petter Selasky for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
346*d6b92ffaSHans Petter Selasky item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
347*d6b92ffaSHans Petter Selasky item = cl_qmap_next(item)) {
348*d6b92ffaSHans Petter Selasky p_sw = (osm_switch_t *)item;
349*d6b92ffaSHans Petter Selasky dnup_bfs_by_node(p_log, p_subn, p_sw, max_hops + 1, NULL);
350*d6b92ffaSHans Petter Selasky }
351*d6b92ffaSHans Petter Selasky }
352*d6b92ffaSHans Petter Selasky
353*d6b92ffaSHans Petter Selasky OSM_LOG(p_log, OSM_LOG_VERBOSE,
354*d6b92ffaSHans Petter Selasky "BFS through all port guids in the subnet ]\n");
355*d6b92ffaSHans Petter Selasky /* Cleanup */
356*d6b92ffaSHans Petter Selasky OSM_LOG_EXIT(p_log);
357*d6b92ffaSHans Petter Selasky return 0;
358*d6b92ffaSHans Petter Selasky }
359*d6b92ffaSHans Petter Selasky
dnup_build_lid_matrices(IN dnup_t * p_dnup)360*d6b92ffaSHans Petter Selasky static int dnup_build_lid_matrices(IN dnup_t * p_dnup)
361*d6b92ffaSHans Petter Selasky {
362*d6b92ffaSHans Petter Selasky int status;
363*d6b92ffaSHans Petter Selasky
364*d6b92ffaSHans Petter Selasky OSM_LOG_ENTER(&p_dnup->p_osm->log);
365*d6b92ffaSHans Petter Selasky
366*d6b92ffaSHans Petter Selasky OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
367*d6b92ffaSHans Petter Selasky "Ranking all port guids in the list\n");
368*d6b92ffaSHans Petter Selasky /* Check if it's not a switched subnet */
369*d6b92ffaSHans Petter Selasky if (cl_is_qmap_empty(&p_dnup->p_osm->subn.sw_guid_tbl)) {
370*d6b92ffaSHans Petter Selasky OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_ERROR, "ERR AEOB: "
371*d6b92ffaSHans Petter Selasky "This is not a switched subnet, cannot perform DNUP algorithm\n");
372*d6b92ffaSHans Petter Selasky status = -1;
373*d6b92ffaSHans Petter Selasky goto _exit;
374*d6b92ffaSHans Petter Selasky }
375*d6b92ffaSHans Petter Selasky
376*d6b92ffaSHans Petter Selasky /* Rank the subnet switches */
377*d6b92ffaSHans Petter Selasky dnup_subn_rank(p_dnup);
378*d6b92ffaSHans Petter Selasky
379*d6b92ffaSHans Petter Selasky /* After multiple ranking need to set Min Hop Table by DnUp algorithm */
380*d6b92ffaSHans Petter Selasky OSM_LOG(&p_dnup->p_osm->log, OSM_LOG_VERBOSE,
381*d6b92ffaSHans Petter Selasky "Setting all switches' Min Hop Table\n");
382*d6b92ffaSHans Petter Selasky status = dnup_set_min_hop_table(p_dnup);
383*d6b92ffaSHans Petter Selasky
384*d6b92ffaSHans Petter Selasky _exit:
385*d6b92ffaSHans Petter Selasky OSM_LOG_EXIT(&p_dnup->p_osm->log);
386*d6b92ffaSHans Petter Selasky return status;
387*d6b92ffaSHans Petter Selasky }
388*d6b92ffaSHans Petter Selasky
create_dnup_node(osm_switch_t * sw)389*d6b92ffaSHans Petter Selasky static struct dnup_node *create_dnup_node(osm_switch_t * sw)
390*d6b92ffaSHans Petter Selasky {
391*d6b92ffaSHans Petter Selasky struct dnup_node *u;
392*d6b92ffaSHans Petter Selasky
393*d6b92ffaSHans Petter Selasky u = malloc(sizeof(*u));
394*d6b92ffaSHans Petter Selasky if (!u)
395*d6b92ffaSHans Petter Selasky return NULL;
396*d6b92ffaSHans Petter Selasky memset(u, 0, sizeof(*u));
397*d6b92ffaSHans Petter Selasky u->sw = sw;
398*d6b92ffaSHans Petter Selasky u->rank = 0xffffffff;
399*d6b92ffaSHans Petter Selasky return u;
400*d6b92ffaSHans Petter Selasky }
401*d6b92ffaSHans Petter Selasky
delete_dnup_node(struct dnup_node * u)402*d6b92ffaSHans Petter Selasky static void delete_dnup_node(struct dnup_node *u)
403*d6b92ffaSHans Petter Selasky {
404*d6b92ffaSHans Petter Selasky u->sw->priv = NULL;
405*d6b92ffaSHans Petter Selasky free(u);
406*d6b92ffaSHans Petter Selasky }
407*d6b92ffaSHans Petter Selasky
408*d6b92ffaSHans Petter Selasky /* DNUP callback function */
dnup_lid_matrices(void * ctx)409*d6b92ffaSHans Petter Selasky static int dnup_lid_matrices(void *ctx)
410*d6b92ffaSHans Petter Selasky {
411*d6b92ffaSHans Petter Selasky dnup_t *p_dnup = ctx;
412*d6b92ffaSHans Petter Selasky cl_map_item_t *item;
413*d6b92ffaSHans Petter Selasky osm_switch_t *p_sw;
414*d6b92ffaSHans Petter Selasky int ret = 0;
415*d6b92ffaSHans Petter Selasky int num_leafs = 0;
416*d6b92ffaSHans Petter Selasky uint8_t pn, pn_rem;
417*d6b92ffaSHans Petter Selasky
418*d6b92ffaSHans Petter Selasky OSM_LOG_ENTER(&p_dnup->p_osm->log);
419*d6b92ffaSHans Petter Selasky
420*d6b92ffaSHans Petter Selasky for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
421*d6b92ffaSHans Petter Selasky item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
422*d6b92ffaSHans Petter Selasky item = cl_qmap_next(item)) {
423*d6b92ffaSHans Petter Selasky p_sw = (osm_switch_t *)item;
424*d6b92ffaSHans Petter Selasky p_sw->priv = create_dnup_node(p_sw);
425*d6b92ffaSHans Petter Selasky if (!p_sw->priv) {
426*d6b92ffaSHans Petter Selasky OSM_LOG(&(p_dnup->p_osm->log), OSM_LOG_ERROR, "ERR AE0C: "
427*d6b92ffaSHans Petter Selasky "cannot create dnup node\n");
428*d6b92ffaSHans Petter Selasky OSM_LOG_EXIT(&p_dnup->p_osm->log);
429*d6b92ffaSHans Petter Selasky return -1;
430*d6b92ffaSHans Petter Selasky }
431*d6b92ffaSHans Petter Selasky }
432*d6b92ffaSHans Petter Selasky
433*d6b92ffaSHans Petter Selasky
434*d6b92ffaSHans Petter Selasky /* First setup node level nodes */
435*d6b92ffaSHans Petter Selasky for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
436*d6b92ffaSHans Petter Selasky item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
437*d6b92ffaSHans Petter Selasky item = cl_qmap_next(item)) {
438*d6b92ffaSHans Petter Selasky p_sw = (osm_switch_t *)item;
439*d6b92ffaSHans Petter Selasky
440*d6b92ffaSHans Petter Selasky for (pn = 0; pn < p_sw->num_ports; pn++) {
441*d6b92ffaSHans Petter Selasky osm_node_t *p_remote_node;
442*d6b92ffaSHans Petter Selasky p_remote_node = osm_node_get_remote_node(p_sw->p_node, pn, &pn_rem);
443*d6b92ffaSHans Petter Selasky if(p_remote_node && !p_remote_node->sw) {
444*d6b92ffaSHans Petter Selasky struct dnup_node *u = p_sw->priv;
445*d6b92ffaSHans Petter Selasky u->rank = 0;
446*d6b92ffaSHans Petter Selasky OSM_LOG(&(p_dnup->p_osm->log),
447*d6b92ffaSHans Petter Selasky OSM_LOG_VERBOSE, "(%s) rank 0 leaf switch\n",
448*d6b92ffaSHans Petter Selasky p_sw->p_node->print_desc);
449*d6b92ffaSHans Petter Selasky num_leafs++;
450*d6b92ffaSHans Petter Selasky break;
451*d6b92ffaSHans Petter Selasky }
452*d6b92ffaSHans Petter Selasky }
453*d6b92ffaSHans Petter Selasky }
454*d6b92ffaSHans Petter Selasky
455*d6b92ffaSHans Petter Selasky if(num_leafs == 0) {
456*d6b92ffaSHans Petter Selasky OSM_LOG(&(p_dnup->p_osm->log),
457*d6b92ffaSHans Petter Selasky OSM_LOG_ERROR, "ERR AE0D: No leaf switches found, DnUp routing failed\n");
458*d6b92ffaSHans Petter Selasky OSM_LOG_EXIT(&p_dnup->p_osm->log);
459*d6b92ffaSHans Petter Selasky return -1;
460*d6b92ffaSHans Petter Selasky }
461*d6b92ffaSHans Petter Selasky
462*d6b92ffaSHans Petter Selasky ret = dnup_build_lid_matrices(p_dnup);
463*d6b92ffaSHans Petter Selasky
464*d6b92ffaSHans Petter Selasky for (item = cl_qmap_head(&p_dnup->p_osm->subn.sw_guid_tbl);
465*d6b92ffaSHans Petter Selasky item != cl_qmap_end(&p_dnup->p_osm->subn.sw_guid_tbl);
466*d6b92ffaSHans Petter Selasky item = cl_qmap_next(item)) {
467*d6b92ffaSHans Petter Selasky p_sw = (osm_switch_t *) item;
468*d6b92ffaSHans Petter Selasky delete_dnup_node(p_sw->priv);
469*d6b92ffaSHans Petter Selasky }
470*d6b92ffaSHans Petter Selasky
471*d6b92ffaSHans Petter Selasky OSM_LOG_EXIT(&p_dnup->p_osm->log);
472*d6b92ffaSHans Petter Selasky return ret;
473*d6b92ffaSHans Petter Selasky }
474*d6b92ffaSHans Petter Selasky
dnup_delete(void * context)475*d6b92ffaSHans Petter Selasky static void dnup_delete(void *context)
476*d6b92ffaSHans Petter Selasky {
477*d6b92ffaSHans Petter Selasky free(context);
478*d6b92ffaSHans Petter Selasky }
479*d6b92ffaSHans Petter Selasky
osm_ucast_dnup_setup(struct osm_routing_engine * r,osm_opensm_t * osm)480*d6b92ffaSHans Petter Selasky int osm_ucast_dnup_setup(struct osm_routing_engine *r, osm_opensm_t *osm)
481*d6b92ffaSHans Petter Selasky {
482*d6b92ffaSHans Petter Selasky dnup_t *dnup;
483*d6b92ffaSHans Petter Selasky
484*d6b92ffaSHans Petter Selasky OSM_LOG_ENTER(&osm->log);
485*d6b92ffaSHans Petter Selasky
486*d6b92ffaSHans Petter Selasky dnup = malloc(sizeof(dnup_t));
487*d6b92ffaSHans Petter Selasky if (!dnup)
488*d6b92ffaSHans Petter Selasky return -1;
489*d6b92ffaSHans Petter Selasky memset(dnup, 0, sizeof(dnup_t));
490*d6b92ffaSHans Petter Selasky
491*d6b92ffaSHans Petter Selasky dnup->p_osm = osm;
492*d6b92ffaSHans Petter Selasky
493*d6b92ffaSHans Petter Selasky r->context = dnup;
494*d6b92ffaSHans Petter Selasky r->destroy = dnup_delete;
495*d6b92ffaSHans Petter Selasky r->build_lid_matrices = dnup_lid_matrices;
496*d6b92ffaSHans Petter Selasky
497*d6b92ffaSHans Petter Selasky OSM_LOG_EXIT(&osm->log);
498*d6b92ffaSHans Petter Selasky return 0;
499*d6b92ffaSHans Petter Selasky }
500