1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2008-2009 Voltaire, Inc. All rights reserved.
3d6b92ffaSHans Petter Selasky  * Copyright (c) 2008-2009 Mellanox Technologies LTD. All rights reserved.
4d6b92ffaSHans Petter Selasky  *
5d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
6d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
7d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
8d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
9d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
10d6b92ffaSHans Petter Selasky  *
11d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
12d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
13d6b92ffaSHans Petter Selasky  *     conditions are met:
14d6b92ffaSHans Petter Selasky  *
15d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
16d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
17d6b92ffaSHans Petter Selasky  *        disclaimer.
18d6b92ffaSHans Petter Selasky  *
19d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
20d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
21d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
22d6b92ffaSHans Petter Selasky  *        provided with the distribution.
23d6b92ffaSHans Petter Selasky  *
24d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31d6b92ffaSHans Petter Selasky  * SOFTWARE.
32d6b92ffaSHans Petter Selasky  *
33d6b92ffaSHans Petter Selasky  */
34d6b92ffaSHans Petter Selasky 
35d6b92ffaSHans Petter Selasky /*
36d6b92ffaSHans Petter Selasky  * Abstract:
37d6b92ffaSHans Petter Selasky  *    Implementation of OpenSM Cached Unicast Routing
38d6b92ffaSHans Petter Selasky  *
39d6b92ffaSHans Petter Selasky  * Environment:
40d6b92ffaSHans Petter Selasky  *    Linux User Mode
41d6b92ffaSHans Petter Selasky  *
42d6b92ffaSHans Petter Selasky  */
43d6b92ffaSHans Petter Selasky 
44d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H
45d6b92ffaSHans Petter Selasky #  include <config.h>
46d6b92ffaSHans Petter Selasky #endif
47d6b92ffaSHans Petter Selasky 
48d6b92ffaSHans Petter Selasky #include <stdlib.h>
49d6b92ffaSHans Petter Selasky #include <string.h>
50d6b92ffaSHans Petter Selasky #include <ctype.h>
51d6b92ffaSHans Petter Selasky #include <errno.h>
52d6b92ffaSHans Petter Selasky #include <iba/ib_types.h>
53d6b92ffaSHans Petter Selasky #include <complib/cl_qmap.h>
54d6b92ffaSHans Petter Selasky #include <complib/cl_pool.h>
55d6b92ffaSHans Petter Selasky #include <complib/cl_debug.h>
56d6b92ffaSHans Petter Selasky #include <opensm/osm_file_ids.h>
57d6b92ffaSHans Petter Selasky #define FILE_ID OSM_FILE_UCAST_CACHE_C
58d6b92ffaSHans Petter Selasky #include <opensm/osm_opensm.h>
59d6b92ffaSHans Petter Selasky #include <opensm/osm_ucast_mgr.h>
60d6b92ffaSHans Petter Selasky #include <opensm/osm_ucast_cache.h>
61d6b92ffaSHans Petter Selasky #include <opensm/osm_switch.h>
62d6b92ffaSHans Petter Selasky #include <opensm/osm_node.h>
63d6b92ffaSHans Petter Selasky #include <opensm/osm_port.h>
64d6b92ffaSHans Petter Selasky 
65d6b92ffaSHans Petter Selasky typedef struct cache_port {
66d6b92ffaSHans Petter Selasky 	boolean_t is_leaf;
67d6b92ffaSHans Petter Selasky 	uint16_t remote_lid_ho;
68d6b92ffaSHans Petter Selasky } cache_port_t;
69d6b92ffaSHans Petter Selasky 
70d6b92ffaSHans Petter Selasky typedef struct cache_switch {
71d6b92ffaSHans Petter Selasky 	cl_map_item_t map_item;
72d6b92ffaSHans Petter Selasky 	boolean_t dropped;
73d6b92ffaSHans Petter Selasky 	uint16_t max_lid_ho;
74d6b92ffaSHans Petter Selasky 	uint16_t num_hops;
75d6b92ffaSHans Petter Selasky 	uint8_t **hops;
76d6b92ffaSHans Petter Selasky 	uint8_t *lft;
77d6b92ffaSHans Petter Selasky 	uint8_t num_ports;
78d6b92ffaSHans Petter Selasky 	cache_port_t ports[0];
79d6b92ffaSHans Petter Selasky } cache_switch_t;
80d6b92ffaSHans Petter Selasky 
cache_sw_get_base_lid_ho(cache_switch_t * p_sw)81d6b92ffaSHans Petter Selasky static uint16_t cache_sw_get_base_lid_ho(cache_switch_t * p_sw)
82d6b92ffaSHans Petter Selasky {
83d6b92ffaSHans Petter Selasky 	return p_sw->ports[0].remote_lid_ho;
84d6b92ffaSHans Petter Selasky }
85d6b92ffaSHans Petter Selasky 
cache_sw_is_leaf(cache_switch_t * p_sw)86d6b92ffaSHans Petter Selasky static boolean_t cache_sw_is_leaf(cache_switch_t * p_sw)
87d6b92ffaSHans Petter Selasky {
88d6b92ffaSHans Petter Selasky 	return p_sw->ports[0].is_leaf;
89d6b92ffaSHans Petter Selasky }
90d6b92ffaSHans Petter Selasky 
cache_sw_set_leaf(cache_switch_t * p_sw)91d6b92ffaSHans Petter Selasky static void cache_sw_set_leaf(cache_switch_t * p_sw)
92d6b92ffaSHans Petter Selasky {
93d6b92ffaSHans Petter Selasky 	p_sw->ports[0].is_leaf = TRUE;
94d6b92ffaSHans Petter Selasky }
95d6b92ffaSHans Petter Selasky 
cache_sw_new(uint16_t lid_ho,unsigned num_ports)96d6b92ffaSHans Petter Selasky static cache_switch_t *cache_sw_new(uint16_t lid_ho, unsigned num_ports)
97d6b92ffaSHans Petter Selasky {
98d6b92ffaSHans Petter Selasky 	cache_switch_t *p_cache_sw = malloc(sizeof(cache_switch_t) +
99d6b92ffaSHans Petter Selasky 					    num_ports * sizeof(cache_port_t));
100d6b92ffaSHans Petter Selasky 	if (!p_cache_sw)
101d6b92ffaSHans Petter Selasky 		return NULL;
102d6b92ffaSHans Petter Selasky 
103d6b92ffaSHans Petter Selasky 	memset(p_cache_sw, 0,
104d6b92ffaSHans Petter Selasky 	       sizeof(*p_cache_sw) + num_ports * sizeof(cache_port_t));
105d6b92ffaSHans Petter Selasky 
106d6b92ffaSHans Petter Selasky 	p_cache_sw->num_ports = num_ports;
107d6b92ffaSHans Petter Selasky 
108d6b92ffaSHans Petter Selasky 	/* port[0] fields represent this switch details - lid and type */
109d6b92ffaSHans Petter Selasky 	p_cache_sw->ports[0].remote_lid_ho = lid_ho;
110d6b92ffaSHans Petter Selasky 	p_cache_sw->ports[0].is_leaf = FALSE;
111d6b92ffaSHans Petter Selasky 
112d6b92ffaSHans Petter Selasky 	return p_cache_sw;
113d6b92ffaSHans Petter Selasky }
114d6b92ffaSHans Petter Selasky 
cache_sw_destroy(cache_switch_t * p_sw)115d6b92ffaSHans Petter Selasky static void cache_sw_destroy(cache_switch_t * p_sw)
116d6b92ffaSHans Petter Selasky {
117d6b92ffaSHans Petter Selasky 	unsigned i;
118d6b92ffaSHans Petter Selasky 
119d6b92ffaSHans Petter Selasky 	if (!p_sw)
120d6b92ffaSHans Petter Selasky 		return;
121d6b92ffaSHans Petter Selasky 
122d6b92ffaSHans Petter Selasky 	if (p_sw->lft)
123d6b92ffaSHans Petter Selasky 		free(p_sw->lft);
124d6b92ffaSHans Petter Selasky 	if (p_sw->hops) {
125d6b92ffaSHans Petter Selasky 		for (i = 0; i < p_sw->num_hops; i++)
126d6b92ffaSHans Petter Selasky 			if (p_sw->hops[i])
127d6b92ffaSHans Petter Selasky 				free(p_sw->hops[i]);
128d6b92ffaSHans Petter Selasky 		free(p_sw->hops);
129d6b92ffaSHans Petter Selasky 	}
130d6b92ffaSHans Petter Selasky 	free(p_sw);
131d6b92ffaSHans Petter Selasky }
132d6b92ffaSHans Petter Selasky 
cache_get_sw(osm_ucast_mgr_t * p_mgr,uint16_t lid_ho)133d6b92ffaSHans Petter Selasky static cache_switch_t *cache_get_sw(osm_ucast_mgr_t * p_mgr, uint16_t lid_ho)
134d6b92ffaSHans Petter Selasky {
135d6b92ffaSHans Petter Selasky 	cache_switch_t *p_cache_sw = (cache_switch_t *)
136d6b92ffaSHans Petter Selasky 	    cl_qmap_get(&p_mgr->cache_sw_tbl, lid_ho);
137d6b92ffaSHans Petter Selasky 	if (p_cache_sw == (cache_switch_t *)
138d6b92ffaSHans Petter Selasky 	    cl_qmap_end(&p_mgr->cache_sw_tbl))
139d6b92ffaSHans Petter Selasky 		p_cache_sw = NULL;
140d6b92ffaSHans Petter Selasky 
141d6b92ffaSHans Petter Selasky 	return p_cache_sw;
142d6b92ffaSHans Petter Selasky }
143d6b92ffaSHans Petter Selasky 
cache_add_sw_link(osm_ucast_mgr_t * p_mgr,osm_physp_t * p,uint16_t remote_lid_ho,boolean_t is_ca)144d6b92ffaSHans Petter Selasky static void cache_add_sw_link(osm_ucast_mgr_t * p_mgr, osm_physp_t *p,
145d6b92ffaSHans Petter Selasky 			      uint16_t remote_lid_ho, boolean_t is_ca)
146d6b92ffaSHans Petter Selasky {
147d6b92ffaSHans Petter Selasky 	cache_switch_t *p_cache_sw;
148d6b92ffaSHans Petter Selasky 	uint16_t lid_ho = cl_ntoh16(osm_node_get_base_lid(p->p_node, 0));
149d6b92ffaSHans Petter Selasky 
150d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
151d6b92ffaSHans Petter Selasky 
152d6b92ffaSHans Petter Selasky 	if (!lid_ho || !remote_lid_ho || !p->port_num)
153d6b92ffaSHans Petter Selasky 		goto Exit;
154d6b92ffaSHans Petter Selasky 
155d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
156d6b92ffaSHans Petter Selasky 		"Caching switch port: lid %u [port %u] -> lid %u (%s)\n",
157d6b92ffaSHans Petter Selasky 		lid_ho, p->port_num, remote_lid_ho, (is_ca) ? "CA/RTR" : "SW");
158d6b92ffaSHans Petter Selasky 
159d6b92ffaSHans Petter Selasky 	p_cache_sw = cache_get_sw(p_mgr, lid_ho);
160d6b92ffaSHans Petter Selasky 	if (!p_cache_sw) {
161d6b92ffaSHans Petter Selasky 		p_cache_sw = cache_sw_new(lid_ho, p->p_node->sw->num_ports);
162d6b92ffaSHans Petter Selasky 		if (!p_cache_sw) {
163d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
164d6b92ffaSHans Petter Selasky 				"ERR AD01: Out of memory - cache is invalid\n");
165d6b92ffaSHans Petter Selasky 			osm_ucast_cache_invalidate(p_mgr);
166d6b92ffaSHans Petter Selasky 			goto Exit;
167d6b92ffaSHans Petter Selasky 		}
168d6b92ffaSHans Petter Selasky 		cl_qmap_insert(&p_mgr->cache_sw_tbl, lid_ho,
169d6b92ffaSHans Petter Selasky 			       &p_cache_sw->map_item);
170d6b92ffaSHans Petter Selasky 	}
171d6b92ffaSHans Petter Selasky 
172d6b92ffaSHans Petter Selasky 	if (p->port_num >= p_cache_sw->num_ports) {
173d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
174d6b92ffaSHans Petter Selasky 			"ERR AD02: Wrong switch? - cache is invalid\n");
175d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
176d6b92ffaSHans Petter Selasky 		goto Exit;
177d6b92ffaSHans Petter Selasky 	}
178d6b92ffaSHans Petter Selasky 
179d6b92ffaSHans Petter Selasky 	if (is_ca)
180d6b92ffaSHans Petter Selasky 		cache_sw_set_leaf(p_cache_sw);
181d6b92ffaSHans Petter Selasky 
182d6b92ffaSHans Petter Selasky 	if (p_cache_sw->ports[p->port_num].remote_lid_ho == 0) {
183d6b92ffaSHans Petter Selasky 		/* cache this link only if it hasn't been already cached */
184d6b92ffaSHans Petter Selasky 		p_cache_sw->ports[p->port_num].remote_lid_ho = remote_lid_ho;
185d6b92ffaSHans Petter Selasky 		p_cache_sw->ports[p->port_num].is_leaf = is_ca;
186d6b92ffaSHans Petter Selasky 	}
187d6b92ffaSHans Petter Selasky Exit:
188d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
189d6b92ffaSHans Petter Selasky }
190d6b92ffaSHans Petter Selasky 
cache_cleanup_switches(osm_ucast_mgr_t * p_mgr)191d6b92ffaSHans Petter Selasky static void cache_cleanup_switches(osm_ucast_mgr_t * p_mgr)
192d6b92ffaSHans Petter Selasky {
193d6b92ffaSHans Petter Selasky 	cache_switch_t *p_sw;
194d6b92ffaSHans Petter Selasky 	cache_switch_t *p_next_sw;
195d6b92ffaSHans Petter Selasky 	unsigned port_num;
196d6b92ffaSHans Petter Selasky 	boolean_t found_port;
197d6b92ffaSHans Petter Selasky 
198d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
199d6b92ffaSHans Petter Selasky 		return;
200d6b92ffaSHans Petter Selasky 
201d6b92ffaSHans Petter Selasky 	p_next_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl);
202d6b92ffaSHans Petter Selasky 	while (p_next_sw !=
203d6b92ffaSHans Petter Selasky 	       (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl)) {
204d6b92ffaSHans Petter Selasky 		p_sw = p_next_sw;
205d6b92ffaSHans Petter Selasky 		p_next_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item);
206d6b92ffaSHans Petter Selasky 
207d6b92ffaSHans Petter Selasky 		found_port = FALSE;
208d6b92ffaSHans Petter Selasky 		for (port_num = 1; port_num < p_sw->num_ports; port_num++)
209d6b92ffaSHans Petter Selasky 			if (p_sw->ports[port_num].remote_lid_ho)
210d6b92ffaSHans Petter Selasky 				found_port = TRUE;
211d6b92ffaSHans Petter Selasky 
212d6b92ffaSHans Petter Selasky 		if (!found_port) {
213d6b92ffaSHans Petter Selasky 			cl_qmap_remove_item(&p_mgr->cache_sw_tbl,
214d6b92ffaSHans Petter Selasky 					    &p_sw->map_item);
215d6b92ffaSHans Petter Selasky 			cache_sw_destroy(p_sw);
216d6b92ffaSHans Petter Selasky 		}
217d6b92ffaSHans Petter Selasky 	}
218d6b92ffaSHans Petter Selasky }
219d6b92ffaSHans Petter Selasky 
220d6b92ffaSHans Petter Selasky static void
cache_check_link_change(osm_ucast_mgr_t * p_mgr,osm_physp_t * p_physp_1,osm_physp_t * p_physp_2)221d6b92ffaSHans Petter Selasky cache_check_link_change(osm_ucast_mgr_t * p_mgr,
222d6b92ffaSHans Petter Selasky 			osm_physp_t * p_physp_1, osm_physp_t * p_physp_2)
223d6b92ffaSHans Petter Selasky {
224d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
225d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_physp_1 && p_physp_2);
226d6b92ffaSHans Petter Selasky 
227d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
228d6b92ffaSHans Petter Selasky 		goto Exit;
229d6b92ffaSHans Petter Selasky 
230d6b92ffaSHans Petter Selasky 	if (!p_physp_1->p_remote_physp && !p_physp_2->p_remote_physp)
231d6b92ffaSHans Petter Selasky 		/* both ports were down - new link */
232d6b92ffaSHans Petter Selasky 		goto Exit;
233d6b92ffaSHans Petter Selasky 
234d6b92ffaSHans Petter Selasky 	/* unicast cache cannot tolerate any link location change */
235d6b92ffaSHans Petter Selasky 
236d6b92ffaSHans Petter Selasky 	if ((p_physp_1->p_remote_physp &&
237d6b92ffaSHans Petter Selasky 	     p_physp_1->p_remote_physp->p_remote_physp) ||
238d6b92ffaSHans Petter Selasky 	    (p_physp_2->p_remote_physp &&
239d6b92ffaSHans Petter Selasky 	     p_physp_2->p_remote_physp->p_remote_physp)) {
240d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
241d6b92ffaSHans Petter Selasky 			"Link location change discovered\n");
242d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
243d6b92ffaSHans Petter Selasky 		goto Exit;
244d6b92ffaSHans Petter Selasky 	}
245d6b92ffaSHans Petter Selasky Exit:
246d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
247d6b92ffaSHans Petter Selasky }
248d6b92ffaSHans Petter Selasky 
cache_remove_port(osm_ucast_mgr_t * p_mgr,uint16_t lid_ho,uint8_t port_num,uint16_t remote_lid_ho,boolean_t is_ca)249d6b92ffaSHans Petter Selasky static void cache_remove_port(osm_ucast_mgr_t * p_mgr, uint16_t lid_ho,
250d6b92ffaSHans Petter Selasky 			      uint8_t port_num, uint16_t remote_lid_ho,
251d6b92ffaSHans Petter Selasky 			      boolean_t is_ca)
252d6b92ffaSHans Petter Selasky {
253d6b92ffaSHans Petter Selasky 	cache_switch_t *p_cache_sw;
254d6b92ffaSHans Petter Selasky 
255d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
256d6b92ffaSHans Petter Selasky 
257d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
258d6b92ffaSHans Petter Selasky 		goto Exit;
259d6b92ffaSHans Petter Selasky 
260d6b92ffaSHans Petter Selasky 	p_cache_sw = cache_get_sw(p_mgr, lid_ho);
261d6b92ffaSHans Petter Selasky 	if (!p_cache_sw) {
262d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
263d6b92ffaSHans Petter Selasky 			"Found uncached switch/link (lid %u, port %u)\n",
264d6b92ffaSHans Petter Selasky 			lid_ho, port_num);
265d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
266d6b92ffaSHans Petter Selasky 		goto Exit;
267d6b92ffaSHans Petter Selasky 	}
268d6b92ffaSHans Petter Selasky 
269d6b92ffaSHans Petter Selasky 	if (port_num >= p_cache_sw->num_ports ||
270d6b92ffaSHans Petter Selasky 	    !p_cache_sw->ports[port_num].remote_lid_ho) {
271d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
272d6b92ffaSHans Petter Selasky 			"Found uncached switch link (lid %u, port %u)\n",
273d6b92ffaSHans Petter Selasky 			lid_ho, port_num);
274d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
275d6b92ffaSHans Petter Selasky 		goto Exit;
276d6b92ffaSHans Petter Selasky 	}
277d6b92ffaSHans Petter Selasky 
278d6b92ffaSHans Petter Selasky 	if (p_cache_sw->ports[port_num].remote_lid_ho != remote_lid_ho) {
279d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
280d6b92ffaSHans Petter Selasky 			"Remote lid change on switch lid %u, port %u "
281d6b92ffaSHans Petter Selasky 			"(was %u, now %u)\n", lid_ho, port_num,
282d6b92ffaSHans Petter Selasky 			p_cache_sw->ports[port_num].remote_lid_ho,
283d6b92ffaSHans Petter Selasky 			remote_lid_ho);
284d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
285d6b92ffaSHans Petter Selasky 		goto Exit;
286d6b92ffaSHans Petter Selasky 	}
287d6b92ffaSHans Petter Selasky 
288d6b92ffaSHans Petter Selasky 	if ((p_cache_sw->ports[port_num].is_leaf && !is_ca) ||
289d6b92ffaSHans Petter Selasky 	    (!p_cache_sw->ports[port_num].is_leaf && is_ca)) {
290d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
291d6b92ffaSHans Petter Selasky 			"Remote node type change on switch lid %u, port %u\n",
292d6b92ffaSHans Petter Selasky 			lid_ho, port_num);
293d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
294d6b92ffaSHans Petter Selasky 		goto Exit;
295d6b92ffaSHans Petter Selasky 	}
296d6b92ffaSHans Petter Selasky 
297d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
298d6b92ffaSHans Petter Selasky 		"New link from lid %u, port %u to lid %u - "
299d6b92ffaSHans Petter Selasky 		"found in cache\n", lid_ho, port_num, remote_lid_ho);
300d6b92ffaSHans Petter Selasky 
301d6b92ffaSHans Petter Selasky 	/* the new link was cached - clean it from the cache */
302d6b92ffaSHans Petter Selasky 
303d6b92ffaSHans Petter Selasky 	p_cache_sw->ports[port_num].remote_lid_ho = 0;
304d6b92ffaSHans Petter Selasky 	p_cache_sw->ports[port_num].is_leaf = FALSE;
305d6b92ffaSHans Petter Selasky Exit:
306d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
307d6b92ffaSHans Petter Selasky }				/* cache_remove_port() */
308d6b92ffaSHans Petter Selasky 
309d6b92ffaSHans Petter Selasky static void
cache_restore_ucast_info(osm_ucast_mgr_t * p_mgr,cache_switch_t * p_cache_sw,osm_switch_t * p_sw)310d6b92ffaSHans Petter Selasky cache_restore_ucast_info(osm_ucast_mgr_t * p_mgr,
311d6b92ffaSHans Petter Selasky 			 cache_switch_t * p_cache_sw, osm_switch_t * p_sw)
312d6b92ffaSHans Petter Selasky {
313d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
314d6b92ffaSHans Petter Selasky 		return;
315d6b92ffaSHans Petter Selasky 
316d6b92ffaSHans Petter Selasky 	/* when seting unicast info, the cached port
317d6b92ffaSHans Petter Selasky 	   should have all the required info */
318d6b92ffaSHans Petter Selasky 	CL_ASSERT(p_cache_sw->max_lid_ho && p_cache_sw->lft &&
319d6b92ffaSHans Petter Selasky 		  p_cache_sw->num_hops && p_cache_sw->hops);
320d6b92ffaSHans Petter Selasky 
321d6b92ffaSHans Petter Selasky 	p_sw->max_lid_ho = p_cache_sw->max_lid_ho;
322d6b92ffaSHans Petter Selasky 
323d6b92ffaSHans Petter Selasky 	if (p_sw->new_lft)
324d6b92ffaSHans Petter Selasky 		free(p_sw->new_lft);
325d6b92ffaSHans Petter Selasky 	p_sw->new_lft = p_cache_sw->lft;
326d6b92ffaSHans Petter Selasky 	p_cache_sw->lft = NULL;
327d6b92ffaSHans Petter Selasky 
328d6b92ffaSHans Petter Selasky 	p_sw->num_hops = p_cache_sw->num_hops;
329d6b92ffaSHans Petter Selasky 	p_cache_sw->num_hops = 0;
330d6b92ffaSHans Petter Selasky 	if (p_sw->hops)
331d6b92ffaSHans Petter Selasky 		free(p_sw->hops);
332d6b92ffaSHans Petter Selasky 	p_sw->hops = p_cache_sw->hops;
333d6b92ffaSHans Petter Selasky 	p_cache_sw->hops = NULL;
334d6b92ffaSHans Petter Selasky 
335d6b92ffaSHans Petter Selasky 	p_sw->need_update = 2;
336d6b92ffaSHans Petter Selasky }
337d6b92ffaSHans Petter Selasky 
ucast_cache_dump(osm_ucast_mgr_t * p_mgr)338d6b92ffaSHans Petter Selasky static void ucast_cache_dump(osm_ucast_mgr_t * p_mgr)
339d6b92ffaSHans Petter Selasky {
340d6b92ffaSHans Petter Selasky 	cache_switch_t *p_sw;
341d6b92ffaSHans Petter Selasky 	unsigned i;
342d6b92ffaSHans Petter Selasky 
343d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
344d6b92ffaSHans Petter Selasky 
345d6b92ffaSHans Petter Selasky 	if (!OSM_LOG_IS_ACTIVE_V2(p_mgr->p_log, OSM_LOG_DEBUG))
346d6b92ffaSHans Petter Selasky 		goto Exit;
347d6b92ffaSHans Petter Selasky 
348d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
349d6b92ffaSHans Petter Selasky 		"Dumping missing nodes/links as logged by unicast cache:\n");
350d6b92ffaSHans Petter Selasky 	for (p_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl);
351d6b92ffaSHans Petter Selasky 	     p_sw != (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl);
352d6b92ffaSHans Petter Selasky 	     p_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item)) {
353d6b92ffaSHans Petter Selasky 
354d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
355d6b92ffaSHans Petter Selasky 			"\t Switch lid %u %s%s\n",
356d6b92ffaSHans Petter Selasky 			cache_sw_get_base_lid_ho(p_sw),
357d6b92ffaSHans Petter Selasky 			(cache_sw_is_leaf(p_sw)) ? "[leaf switch] " : "",
358d6b92ffaSHans Petter Selasky 			(p_sw->dropped) ? "[whole switch missing]" : "");
359d6b92ffaSHans Petter Selasky 
360d6b92ffaSHans Petter Selasky 		for (i = 1; i < p_sw->num_ports; i++)
361d6b92ffaSHans Petter Selasky 			if (p_sw->ports[i].remote_lid_ho > 0)
362d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log,
363d6b92ffaSHans Petter Selasky 					OSM_LOG_DEBUG,
364d6b92ffaSHans Petter Selasky 					"\t     - port %u -> lid %u %s\n",
365d6b92ffaSHans Petter Selasky 					i, p_sw->ports[i].remote_lid_ho,
366d6b92ffaSHans Petter Selasky 					(p_sw->ports[i].is_leaf) ?
367d6b92ffaSHans Petter Selasky 					"[remote node is leaf]" : "");
368d6b92ffaSHans Petter Selasky 	}
369d6b92ffaSHans Petter Selasky Exit:
370d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
371d6b92ffaSHans Petter Selasky }
372d6b92ffaSHans Petter Selasky 
osm_ucast_cache_invalidate(osm_ucast_mgr_t * p_mgr)373d6b92ffaSHans Petter Selasky void osm_ucast_cache_invalidate(osm_ucast_mgr_t * p_mgr)
374d6b92ffaSHans Petter Selasky {
375d6b92ffaSHans Petter Selasky 	cache_switch_t *p_sw;
376d6b92ffaSHans Petter Selasky 	cache_switch_t *p_next_sw;
377d6b92ffaSHans Petter Selasky 
378d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
379d6b92ffaSHans Petter Selasky 
380d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
381d6b92ffaSHans Petter Selasky 		goto Exit;
382d6b92ffaSHans Petter Selasky 
383d6b92ffaSHans Petter Selasky 	p_mgr->cache_valid = FALSE;
384d6b92ffaSHans Petter Selasky 
385d6b92ffaSHans Petter Selasky 	p_next_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl);
386d6b92ffaSHans Petter Selasky 	while (p_next_sw !=
387d6b92ffaSHans Petter Selasky 	       (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl)) {
388d6b92ffaSHans Petter Selasky 		p_sw = p_next_sw;
389d6b92ffaSHans Petter Selasky 		p_next_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item);
390d6b92ffaSHans Petter Selasky 		cache_sw_destroy(p_sw);
391d6b92ffaSHans Petter Selasky 	}
392d6b92ffaSHans Petter Selasky 	cl_qmap_remove_all(&p_mgr->cache_sw_tbl);
393d6b92ffaSHans Petter Selasky 
394d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE, "Unicast Cache invalidated\n");
395d6b92ffaSHans Petter Selasky Exit:
396d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
397d6b92ffaSHans Petter Selasky }
398d6b92ffaSHans Petter Selasky 
ucast_cache_validate(osm_ucast_mgr_t * p_mgr)399d6b92ffaSHans Petter Selasky static void ucast_cache_validate(osm_ucast_mgr_t * p_mgr)
400d6b92ffaSHans Petter Selasky {
401d6b92ffaSHans Petter Selasky 	cache_switch_t *p_cache_sw;
402d6b92ffaSHans Petter Selasky 	cache_switch_t *p_remote_cache_sw;
403d6b92ffaSHans Petter Selasky 	unsigned port_num;
404d6b92ffaSHans Petter Selasky 	unsigned max_ports;
405d6b92ffaSHans Petter Selasky 	uint8_t remote_node_type;
406d6b92ffaSHans Petter Selasky 	uint16_t lid_ho;
407d6b92ffaSHans Petter Selasky 	uint16_t remote_lid_ho;
408d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
409d6b92ffaSHans Petter Selasky 	osm_switch_t *p_remote_sw;
410d6b92ffaSHans Petter Selasky 	osm_node_t *p_node;
411d6b92ffaSHans Petter Selasky 	osm_physp_t *p_physp;
412d6b92ffaSHans Petter Selasky 	osm_physp_t *p_remote_physp;
413d6b92ffaSHans Petter Selasky 	osm_port_t *p_remote_port;
414d6b92ffaSHans Petter Selasky 	cl_qmap_t *p_sw_tbl;
415d6b92ffaSHans Petter Selasky 
416d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
417d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
418d6b92ffaSHans Petter Selasky 		goto Exit;
419d6b92ffaSHans Petter Selasky 
420d6b92ffaSHans Petter Selasky 	/* If there are no switches in the subnet, we are done */
421d6b92ffaSHans Petter Selasky 	p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
422d6b92ffaSHans Petter Selasky 	if (cl_qmap_count(p_sw_tbl) == 0) {
423d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
424d6b92ffaSHans Petter Selasky 		goto Exit;
425d6b92ffaSHans Petter Selasky 	}
426d6b92ffaSHans Petter Selasky 
427d6b92ffaSHans Petter Selasky 	/*
428d6b92ffaSHans Petter Selasky 	 * Scan all the physical switch ports in the subnet.
429d6b92ffaSHans Petter Selasky 	 * If the port need_update flag is on, check whether
430d6b92ffaSHans Petter Selasky 	 * it's just some node/port reset or a cached topology
431d6b92ffaSHans Petter Selasky 	 * change. Otherwise the cache is invalid.
432d6b92ffaSHans Petter Selasky 	 */
433d6b92ffaSHans Petter Selasky 	for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl);
434d6b92ffaSHans Petter Selasky 	     p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl);
435d6b92ffaSHans Petter Selasky 	     p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) {
436d6b92ffaSHans Petter Selasky 
437d6b92ffaSHans Petter Selasky 		p_node = p_sw->p_node;
438d6b92ffaSHans Petter Selasky 
439d6b92ffaSHans Petter Selasky 		lid_ho = cl_ntoh16(osm_node_get_base_lid(p_node, 0));
440d6b92ffaSHans Petter Selasky 		p_cache_sw = cache_get_sw(p_mgr, lid_ho);
441d6b92ffaSHans Petter Selasky 
442d6b92ffaSHans Petter Selasky 		max_ports = osm_node_get_num_physp(p_node);
443d6b92ffaSHans Petter Selasky 
444d6b92ffaSHans Petter Selasky 		/* skip port 0 */
445d6b92ffaSHans Petter Selasky 		for (port_num = 1; port_num < max_ports; port_num++) {
446d6b92ffaSHans Petter Selasky 
447d6b92ffaSHans Petter Selasky 			p_physp = osm_node_get_physp_ptr(p_node, port_num);
448d6b92ffaSHans Petter Selasky 
449d6b92ffaSHans Petter Selasky 			if (!p_physp || !p_physp->p_remote_physp ||
450d6b92ffaSHans Petter Selasky 			    !osm_physp_link_exists(p_physp,
451d6b92ffaSHans Petter Selasky 						   p_physp->p_remote_physp))
452d6b92ffaSHans Petter Selasky 				/* no valid link */
453d6b92ffaSHans Petter Selasky 				continue;
454d6b92ffaSHans Petter Selasky 
455d6b92ffaSHans Petter Selasky 			/*
456d6b92ffaSHans Petter Selasky 			 * While scanning all the physical ports in the subnet,
457d6b92ffaSHans Petter Selasky 			 * mark corresponding leaf switches in the cache.
458d6b92ffaSHans Petter Selasky 			 */
459d6b92ffaSHans Petter Selasky 			if (p_cache_sw &&
460d6b92ffaSHans Petter Selasky 			    !p_cache_sw->dropped &&
461d6b92ffaSHans Petter Selasky 			    !cache_sw_is_leaf(p_cache_sw) &&
462d6b92ffaSHans Petter Selasky 			    p_physp->p_remote_physp->p_node &&
463d6b92ffaSHans Petter Selasky 			    osm_node_get_type(p_physp->p_remote_physp->
464d6b92ffaSHans Petter Selasky 					      p_node) != IB_NODE_TYPE_SWITCH)
465d6b92ffaSHans Petter Selasky 				cache_sw_set_leaf(p_cache_sw);
466d6b92ffaSHans Petter Selasky 
467d6b92ffaSHans Petter Selasky 			if (!p_physp->need_update)
468d6b92ffaSHans Petter Selasky 				continue;
469d6b92ffaSHans Petter Selasky 
470d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
471d6b92ffaSHans Petter Selasky 				"Checking switch lid %u, port %u\n",
472d6b92ffaSHans Petter Selasky 				lid_ho, port_num);
473d6b92ffaSHans Petter Selasky 
474d6b92ffaSHans Petter Selasky 			p_remote_physp = osm_physp_get_remote(p_physp);
475d6b92ffaSHans Petter Selasky 			remote_node_type =
476d6b92ffaSHans Petter Selasky 			    osm_node_get_type(p_remote_physp->p_node);
477d6b92ffaSHans Petter Selasky 
478d6b92ffaSHans Petter Selasky 			if (remote_node_type == IB_NODE_TYPE_SWITCH)
479d6b92ffaSHans Petter Selasky 				remote_lid_ho =
480d6b92ffaSHans Petter Selasky 				    cl_ntoh16(osm_node_get_base_lid
481d6b92ffaSHans Petter Selasky 					      (p_remote_physp->p_node, 0));
482d6b92ffaSHans Petter Selasky 			else
483d6b92ffaSHans Petter Selasky 				remote_lid_ho =
484d6b92ffaSHans Petter Selasky 				    cl_ntoh16(osm_node_get_base_lid
485d6b92ffaSHans Petter Selasky 					      (p_remote_physp->p_node,
486d6b92ffaSHans Petter Selasky 					       osm_physp_get_port_num
487d6b92ffaSHans Petter Selasky 					       (p_remote_physp)));
488d6b92ffaSHans Petter Selasky 
489d6b92ffaSHans Petter Selasky 			if (!p_cache_sw ||
490d6b92ffaSHans Petter Selasky 			    port_num >= p_cache_sw->num_ports ||
491d6b92ffaSHans Petter Selasky 			    !p_cache_sw->ports[port_num].remote_lid_ho) {
492d6b92ffaSHans Petter Selasky 				/*
493d6b92ffaSHans Petter Selasky 				 * There is some uncached change on the port.
494d6b92ffaSHans Petter Selasky 				 * In general, the reasons might be as follows:
495d6b92ffaSHans Petter Selasky 				 *  - switch reset
496d6b92ffaSHans Petter Selasky 				 *  - port reset (or port down/up)
497d6b92ffaSHans Petter Selasky 				 *  - quick connection location change
498d6b92ffaSHans Petter Selasky 				 *  - new link (or new switch)
499d6b92ffaSHans Petter Selasky 				 *
500d6b92ffaSHans Petter Selasky 				 * First two reasons allow cache usage, while
501d6b92ffaSHans Petter Selasky 				 * the last two reasons should invalidate cache.
502d6b92ffaSHans Petter Selasky 				 *
503d6b92ffaSHans Petter Selasky 				 * In case of quick connection location change,
504d6b92ffaSHans Petter Selasky 				 * cache would have been invalidated by
505d6b92ffaSHans Petter Selasky 				 * osm_ucast_cache_check_new_link() function.
506d6b92ffaSHans Petter Selasky 				 *
507d6b92ffaSHans Petter Selasky 				 * In case of new link between two known nodes,
508d6b92ffaSHans Petter Selasky 				 * cache also would have been invalidated by
509d6b92ffaSHans Petter Selasky 				 * osm_ucast_cache_check_new_link() function.
510d6b92ffaSHans Petter Selasky 				 *
511d6b92ffaSHans Petter Selasky 				 * Another reason is cached link between two
512d6b92ffaSHans Petter Selasky 				 * known switches went back. In this case the
513d6b92ffaSHans Petter Selasky 				 * osm_ucast_cache_check_new_link() function would
514d6b92ffaSHans Petter Selasky 				 * clear both sides of the link from the cache
515d6b92ffaSHans Petter Selasky 				 * during the discovery process, so effectively
516d6b92ffaSHans Petter Selasky 				 * this would be equivalent to port reset.
517d6b92ffaSHans Petter Selasky 				 *
518d6b92ffaSHans Petter Selasky 				 * So three possible reasons remain:
519d6b92ffaSHans Petter Selasky 				 *  - switch reset
520d6b92ffaSHans Petter Selasky 				 *  - port reset (or port down/up)
521d6b92ffaSHans Petter Selasky 				 *  - link of a new switch
522d6b92ffaSHans Petter Selasky 				 *
523d6b92ffaSHans Petter Selasky 				 * To validate cache, we need to check only the
524d6b92ffaSHans Petter Selasky 				 * third reason - link of a new node/switch:
525d6b92ffaSHans Petter Selasky 				 *  - If this is the local switch that is new,
526d6b92ffaSHans Petter Selasky 				 *    then it should have (p_sw->need_update == 2).
527d6b92ffaSHans Petter Selasky 				 *  - If the remote node is switch and it's new,
528d6b92ffaSHans Petter Selasky 				 *    then it also should have
529d6b92ffaSHans Petter Selasky 				 *    (p_sw->need_update == 2).
530d6b92ffaSHans Petter Selasky 				 *  - If the remote node is CA/RTR and it's new,
531d6b92ffaSHans Petter Selasky 				 *    then its port should have is_new flag on.
532d6b92ffaSHans Petter Selasky 				 */
533d6b92ffaSHans Petter Selasky 				if (p_sw->need_update == 2) {
534d6b92ffaSHans Petter Selasky 					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
535d6b92ffaSHans Petter Selasky 						"New switch found (lid %u)\n",
536d6b92ffaSHans Petter Selasky 						lid_ho);
537d6b92ffaSHans Petter Selasky 					osm_ucast_cache_invalidate(p_mgr);
538d6b92ffaSHans Petter Selasky 					goto Exit;
539d6b92ffaSHans Petter Selasky 				}
540d6b92ffaSHans Petter Selasky 
541d6b92ffaSHans Petter Selasky 				if (remote_node_type == IB_NODE_TYPE_SWITCH) {
542d6b92ffaSHans Petter Selasky 
543d6b92ffaSHans Petter Selasky 					p_remote_sw =
544d6b92ffaSHans Petter Selasky 					    p_remote_physp->p_node->sw;
545d6b92ffaSHans Petter Selasky 					if (p_remote_sw->need_update == 2) {
546d6b92ffaSHans Petter Selasky 						/* this could also be case of
547d6b92ffaSHans Petter Selasky 						   switch coming back with an
548d6b92ffaSHans Petter Selasky 						   additional link that it
549d6b92ffaSHans Petter Selasky 						   didn't have before */
550d6b92ffaSHans Petter Selasky 						OSM_LOG(p_mgr->p_log,
551d6b92ffaSHans Petter Selasky 							OSM_LOG_DEBUG,
552d6b92ffaSHans Petter Selasky 							"New switch/link found (lid %u)\n",
553d6b92ffaSHans Petter Selasky 							remote_lid_ho);
554d6b92ffaSHans Petter Selasky 						osm_ucast_cache_invalidate
555d6b92ffaSHans Petter Selasky 						    (p_mgr);
556d6b92ffaSHans Petter Selasky 						goto Exit;
557d6b92ffaSHans Petter Selasky 					}
558d6b92ffaSHans Petter Selasky 				} else {
559d6b92ffaSHans Petter Selasky 					/*
560d6b92ffaSHans Petter Selasky 					 * Remote node is CA/RTR.
561d6b92ffaSHans Petter Selasky 					 * Get p_port of the remote node and
562d6b92ffaSHans Petter Selasky 					 * check its p_port->is_new flag.
563d6b92ffaSHans Petter Selasky 					 */
564d6b92ffaSHans Petter Selasky 					p_remote_port =
565d6b92ffaSHans Petter Selasky 					    osm_get_port_by_guid(p_mgr->p_subn,
566d6b92ffaSHans Petter Selasky 								 osm_physp_get_port_guid
567d6b92ffaSHans Petter Selasky 								 (p_remote_physp));
568d6b92ffaSHans Petter Selasky 					if (!p_remote_port) {
569d6b92ffaSHans Petter Selasky 						OSM_LOG(p_mgr->p_log,
570d6b92ffaSHans Petter Selasky 							OSM_LOG_ERROR,
571d6b92ffaSHans Petter Selasky 							"ERR AD04: No port was found for "
572d6b92ffaSHans Petter Selasky 							"port GUID 0x%" PRIx64 "\n",
573d6b92ffaSHans Petter Selasky 							cl_ntoh64(osm_physp_get_port_guid
574d6b92ffaSHans Petter Selasky 								      (p_remote_physp)));
575d6b92ffaSHans Petter Selasky 						osm_ucast_cache_invalidate
576d6b92ffaSHans Petter Selasky 						    (p_mgr);
577d6b92ffaSHans Petter Selasky 						goto Exit;
578d6b92ffaSHans Petter Selasky 					}
579d6b92ffaSHans Petter Selasky 					if (p_remote_port->is_new) {
580d6b92ffaSHans Petter Selasky 						OSM_LOG(p_mgr->p_log,
581d6b92ffaSHans Petter Selasky 							OSM_LOG_DEBUG,
582d6b92ffaSHans Petter Selasky 							"New CA/RTR found (lid %u)\n",
583d6b92ffaSHans Petter Selasky 							remote_lid_ho);
584d6b92ffaSHans Petter Selasky 						osm_ucast_cache_invalidate
585d6b92ffaSHans Petter Selasky 						    (p_mgr);
586d6b92ffaSHans Petter Selasky 						goto Exit;
587d6b92ffaSHans Petter Selasky 					}
588d6b92ffaSHans Petter Selasky 				}
589d6b92ffaSHans Petter Selasky 			} else {
590d6b92ffaSHans Petter Selasky 				/*
591d6b92ffaSHans Petter Selasky 				 * The change on the port is cached.
592d6b92ffaSHans Petter Selasky 				 * In general, the reasons might be as follows:
593d6b92ffaSHans Petter Selasky 				 *  - link between two known nodes went back
594d6b92ffaSHans Petter Selasky 				 *  - one or more nodes went back, causing all
595d6b92ffaSHans Petter Selasky 				 *    the links to reappear
596d6b92ffaSHans Petter Selasky 				 *
597d6b92ffaSHans Petter Selasky 				 * If it was link that went back, then this case
598d6b92ffaSHans Petter Selasky 				 * would have been taken care of during the
599d6b92ffaSHans Petter Selasky 				 * discovery by osm_ucast_cache_check_new_link(),
600d6b92ffaSHans Petter Selasky 				 * so it's some node that went back.
601d6b92ffaSHans Petter Selasky 				 */
602d6b92ffaSHans Petter Selasky 				if ((p_cache_sw->ports[port_num].is_leaf &&
603d6b92ffaSHans Petter Selasky 				     remote_node_type == IB_NODE_TYPE_SWITCH) ||
604d6b92ffaSHans Petter Selasky 				    (!p_cache_sw->ports[port_num].is_leaf &&
605d6b92ffaSHans Petter Selasky 				     remote_node_type != IB_NODE_TYPE_SWITCH)) {
606d6b92ffaSHans Petter Selasky 					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
607d6b92ffaSHans Petter Selasky 						"Remote node type change on switch lid %u, port %u\n",
608d6b92ffaSHans Petter Selasky 						lid_ho, port_num);
609d6b92ffaSHans Petter Selasky 					osm_ucast_cache_invalidate(p_mgr);
610d6b92ffaSHans Petter Selasky 					goto Exit;
611d6b92ffaSHans Petter Selasky 				}
612d6b92ffaSHans Petter Selasky 
613d6b92ffaSHans Petter Selasky 				if (p_cache_sw->ports[port_num].remote_lid_ho !=
614d6b92ffaSHans Petter Selasky 				    remote_lid_ho) {
615d6b92ffaSHans Petter Selasky 					OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
616d6b92ffaSHans Petter Selasky 						"Remote lid change on switch lid %u, port %u"
617d6b92ffaSHans Petter Selasky 						"(was %u, now %u)\n",
618d6b92ffaSHans Petter Selasky 						lid_ho, port_num,
619d6b92ffaSHans Petter Selasky 						p_cache_sw->ports[port_num].
620d6b92ffaSHans Petter Selasky 						remote_lid_ho, remote_lid_ho);
621d6b92ffaSHans Petter Selasky 					osm_ucast_cache_invalidate(p_mgr);
622d6b92ffaSHans Petter Selasky 					goto Exit;
623d6b92ffaSHans Petter Selasky 				}
624d6b92ffaSHans Petter Selasky 
625d6b92ffaSHans Petter Selasky 				/*
626d6b92ffaSHans Petter Selasky 				 * We don't care who is the node that has
627d6b92ffaSHans Petter Selasky 				 * reappeared in the subnet (local or remote).
628d6b92ffaSHans Petter Selasky 				 * What's important that the cached link matches
629d6b92ffaSHans Petter Selasky 				 * the real fabrics link.
630d6b92ffaSHans Petter Selasky 				 * Just clean it from cache.
631d6b92ffaSHans Petter Selasky 				 */
632d6b92ffaSHans Petter Selasky 
633d6b92ffaSHans Petter Selasky 				p_cache_sw->ports[port_num].remote_lid_ho = 0;
634d6b92ffaSHans Petter Selasky 				p_cache_sw->ports[port_num].is_leaf = FALSE;
635d6b92ffaSHans Petter Selasky 				if (p_cache_sw->dropped) {
636d6b92ffaSHans Petter Selasky 					cache_restore_ucast_info(p_mgr,
637d6b92ffaSHans Petter Selasky 								 p_cache_sw,
638d6b92ffaSHans Petter Selasky 								 p_sw);
639d6b92ffaSHans Petter Selasky 					p_cache_sw->dropped = FALSE;
640d6b92ffaSHans Petter Selasky 				}
641d6b92ffaSHans Petter Selasky 
642d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
643d6b92ffaSHans Petter Selasky 					"Restored link from cache: lid %u, port %u to lid %u\n",
644d6b92ffaSHans Petter Selasky 					lid_ho, port_num, remote_lid_ho);
645d6b92ffaSHans Petter Selasky 			}
646d6b92ffaSHans Petter Selasky 		}
647d6b92ffaSHans Petter Selasky 	}
648d6b92ffaSHans Petter Selasky 
649d6b92ffaSHans Petter Selasky 	/* Remove all the cached switches that
650d6b92ffaSHans Petter Selasky 	   have all their ports restored */
651d6b92ffaSHans Petter Selasky 	cache_cleanup_switches(p_mgr);
652d6b92ffaSHans Petter Selasky 
653d6b92ffaSHans Petter Selasky 	/*
654d6b92ffaSHans Petter Selasky 	 * Done scanning all the physical switch ports in the subnet.
655d6b92ffaSHans Petter Selasky 	 * Now we need to check the other side:
656d6b92ffaSHans Petter Selasky 	 * Scan all the cached switches and their ports:
657d6b92ffaSHans Petter Selasky 	 *  - If the cached switch is missing in the subnet
658d6b92ffaSHans Petter Selasky 	 *    (dropped flag is on), check that it's a leaf switch.
659d6b92ffaSHans Petter Selasky 	 *    If it's not a leaf, the cache is invalid, because
660d6b92ffaSHans Petter Selasky 	 *    cache can tolerate only leaf switch removal.
661d6b92ffaSHans Petter Selasky 	 *  - If the cached switch exists in fabric, check all
662d6b92ffaSHans Petter Selasky 	 *    its cached ports. These cached ports represent
663d6b92ffaSHans Petter Selasky 	 *    missing link in the fabric.
664d6b92ffaSHans Petter Selasky 	 *    The missing links that can be tolerated are:
665d6b92ffaSHans Petter Selasky 	 *      + link to missing CA/RTR
666d6b92ffaSHans Petter Selasky 	 *      + link to missing leaf switch
667d6b92ffaSHans Petter Selasky 	 */
668d6b92ffaSHans Petter Selasky 	for (p_cache_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl);
669d6b92ffaSHans Petter Selasky 	     p_cache_sw != (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl);
670d6b92ffaSHans Petter Selasky 	     p_cache_sw =
671d6b92ffaSHans Petter Selasky 	     (cache_switch_t *) cl_qmap_next(&p_cache_sw->map_item)) {
672d6b92ffaSHans Petter Selasky 
673d6b92ffaSHans Petter Selasky 		if (p_cache_sw->dropped) {
674d6b92ffaSHans Petter Selasky 			if (!cache_sw_is_leaf(p_cache_sw)) {
675d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
676d6b92ffaSHans Petter Selasky 					"Missing non-leaf switch (lid %u)\n",
677d6b92ffaSHans Petter Selasky 					cache_sw_get_base_lid_ho(p_cache_sw));
678d6b92ffaSHans Petter Selasky 				osm_ucast_cache_invalidate(p_mgr);
679d6b92ffaSHans Petter Selasky 				goto Exit;
680d6b92ffaSHans Petter Selasky 			}
681d6b92ffaSHans Petter Selasky 
682d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
683d6b92ffaSHans Petter Selasky 				"Missing leaf switch (lid %u) - "
684d6b92ffaSHans Petter Selasky 				"continuing validation\n",
685d6b92ffaSHans Petter Selasky 				cache_sw_get_base_lid_ho(p_cache_sw));
686d6b92ffaSHans Petter Selasky 			continue;
687d6b92ffaSHans Petter Selasky 		}
688d6b92ffaSHans Petter Selasky 
689d6b92ffaSHans Petter Selasky 		for (port_num = 1; port_num < p_cache_sw->num_ports; port_num++) {
690d6b92ffaSHans Petter Selasky 			if (!p_cache_sw->ports[port_num].remote_lid_ho)
691d6b92ffaSHans Petter Selasky 				continue;
692d6b92ffaSHans Petter Selasky 
693d6b92ffaSHans Petter Selasky 			if (p_cache_sw->ports[port_num].is_leaf) {
694d6b92ffaSHans Petter Selasky 				CL_ASSERT(cache_sw_is_leaf(p_cache_sw));
695d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
696d6b92ffaSHans Petter Selasky 					"Switch lid %u, port %u: missing link to CA/RTR - "
697d6b92ffaSHans Petter Selasky 					"continuing validation\n",
698d6b92ffaSHans Petter Selasky 					cache_sw_get_base_lid_ho(p_cache_sw),
699d6b92ffaSHans Petter Selasky 					port_num);
700d6b92ffaSHans Petter Selasky 				continue;
701d6b92ffaSHans Petter Selasky 			}
702d6b92ffaSHans Petter Selasky 
703d6b92ffaSHans Petter Selasky 			p_remote_cache_sw = cache_get_sw(p_mgr,
704d6b92ffaSHans Petter Selasky 							 p_cache_sw->
705d6b92ffaSHans Petter Selasky 							 ports[port_num].
706d6b92ffaSHans Petter Selasky 							 remote_lid_ho);
707d6b92ffaSHans Petter Selasky 
708d6b92ffaSHans Petter Selasky 			if (!p_remote_cache_sw || !p_remote_cache_sw->dropped) {
709d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
710d6b92ffaSHans Petter Selasky 					"Switch lid %u, port %u: missing link to existing switch\n",
711d6b92ffaSHans Petter Selasky 					cache_sw_get_base_lid_ho(p_cache_sw),
712d6b92ffaSHans Petter Selasky 					port_num);
713d6b92ffaSHans Petter Selasky 				osm_ucast_cache_invalidate(p_mgr);
714d6b92ffaSHans Petter Selasky 				goto Exit;
715d6b92ffaSHans Petter Selasky 			}
716d6b92ffaSHans Petter Selasky 
717d6b92ffaSHans Petter Selasky 			if (!cache_sw_is_leaf(p_remote_cache_sw)) {
718d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
719d6b92ffaSHans Petter Selasky 					"Switch lid %u, port %u: missing link to non-leaf switch\n",
720d6b92ffaSHans Petter Selasky 					cache_sw_get_base_lid_ho(p_cache_sw),
721d6b92ffaSHans Petter Selasky 					port_num);
722d6b92ffaSHans Petter Selasky 				osm_ucast_cache_invalidate(p_mgr);
723d6b92ffaSHans Petter Selasky 				goto Exit;
724d6b92ffaSHans Petter Selasky 			}
725d6b92ffaSHans Petter Selasky 
726d6b92ffaSHans Petter Selasky 			/*
727d6b92ffaSHans Petter Selasky 			 * At this point we know that the missing link is to
728d6b92ffaSHans Petter Selasky 			 * a leaf switch. However, one case deserves a special
729d6b92ffaSHans Petter Selasky 			 * treatment. If there was a link between two leaf
730d6b92ffaSHans Petter Selasky 			 * switches, then missing leaf switch might break
731d6b92ffaSHans Petter Selasky 			 * routing. It is possible that there are routes
732d6b92ffaSHans Petter Selasky 			 * that use leaf switches to get from switch to switch
733d6b92ffaSHans Petter Selasky 			 * and not just to get to the CAs behind the leaf switch.
734d6b92ffaSHans Petter Selasky 			 */
735d6b92ffaSHans Petter Selasky 			if (cache_sw_is_leaf(p_cache_sw) &&
736d6b92ffaSHans Petter Selasky 			    cache_sw_is_leaf(p_remote_cache_sw)) {
737d6b92ffaSHans Petter Selasky 				OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
738d6b92ffaSHans Petter Selasky 					"Switch lid %u, port %u: missing leaf-2-leaf link\n",
739d6b92ffaSHans Petter Selasky 					cache_sw_get_base_lid_ho(p_cache_sw),
740d6b92ffaSHans Petter Selasky 					port_num);
741d6b92ffaSHans Petter Selasky 				osm_ucast_cache_invalidate(p_mgr);
742d6b92ffaSHans Petter Selasky 				goto Exit;
743d6b92ffaSHans Petter Selasky 			}
744d6b92ffaSHans Petter Selasky 
745d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
746d6b92ffaSHans Petter Selasky 				"Switch lid %u, port %u: missing remote leaf switch - "
747d6b92ffaSHans Petter Selasky 				"continuing validation\n",
748d6b92ffaSHans Petter Selasky 				cache_sw_get_base_lid_ho(p_cache_sw),
749d6b92ffaSHans Petter Selasky 				port_num);
750d6b92ffaSHans Petter Selasky 		}
751d6b92ffaSHans Petter Selasky 	}
752d6b92ffaSHans Petter Selasky 
753d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "Unicast cache is valid\n");
754d6b92ffaSHans Petter Selasky 	ucast_cache_dump(p_mgr);
755d6b92ffaSHans Petter Selasky Exit:
756d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
757d6b92ffaSHans Petter Selasky }				/* osm_ucast_cache_validate() */
758d6b92ffaSHans Petter Selasky 
osm_ucast_cache_check_new_link(osm_ucast_mgr_t * p_mgr,osm_node_t * p_node_1,uint8_t port_num_1,osm_node_t * p_node_2,uint8_t port_num_2)759d6b92ffaSHans Petter Selasky void osm_ucast_cache_check_new_link(osm_ucast_mgr_t * p_mgr,
760d6b92ffaSHans Petter Selasky 				    osm_node_t * p_node_1, uint8_t port_num_1,
761d6b92ffaSHans Petter Selasky 				    osm_node_t * p_node_2, uint8_t port_num_2)
762d6b92ffaSHans Petter Selasky {
763d6b92ffaSHans Petter Selasky 	uint16_t lid_ho_1;
764d6b92ffaSHans Petter Selasky 	uint16_t lid_ho_2;
765d6b92ffaSHans Petter Selasky 
766d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
767d6b92ffaSHans Petter Selasky 
768d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
769d6b92ffaSHans Petter Selasky 		goto Exit;
770d6b92ffaSHans Petter Selasky 
771d6b92ffaSHans Petter Selasky 	cache_check_link_change(p_mgr,
772d6b92ffaSHans Petter Selasky 				osm_node_get_physp_ptr(p_node_1, port_num_1),
773d6b92ffaSHans Petter Selasky 				osm_node_get_physp_ptr(p_node_2, port_num_2));
774d6b92ffaSHans Petter Selasky 
775d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
776d6b92ffaSHans Petter Selasky 		goto Exit;
777d6b92ffaSHans Petter Selasky 
778d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH &&
779d6b92ffaSHans Petter Selasky 	    osm_node_get_type(p_node_2) != IB_NODE_TYPE_SWITCH) {
780d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "Found CA-2-CA link\n");
781d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
782d6b92ffaSHans Petter Selasky 		goto Exit;
783d6b92ffaSHans Petter Selasky 	}
784d6b92ffaSHans Petter Selasky 
785d6b92ffaSHans Petter Selasky 	/* for code simplicity, we want the first node to be switch */
786d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH) {
787d6b92ffaSHans Petter Selasky 		osm_node_t *tmp_node = p_node_1;
788d6b92ffaSHans Petter Selasky 		uint8_t tmp_port_num = port_num_1;
789d6b92ffaSHans Petter Selasky 		p_node_1 = p_node_2;
790d6b92ffaSHans Petter Selasky 		port_num_1 = port_num_2;
791d6b92ffaSHans Petter Selasky 		p_node_2 = tmp_node;
792d6b92ffaSHans Petter Selasky 		port_num_2 = tmp_port_num;
793d6b92ffaSHans Petter Selasky 	}
794d6b92ffaSHans Petter Selasky 
795d6b92ffaSHans Petter Selasky 	lid_ho_1 = cl_ntoh16(osm_node_get_base_lid(p_node_1, 0));
796d6b92ffaSHans Petter Selasky 
797d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH)
798d6b92ffaSHans Petter Selasky 		lid_ho_2 = cl_ntoh16(osm_node_get_base_lid(p_node_2, 0));
799d6b92ffaSHans Petter Selasky 	else
800d6b92ffaSHans Petter Selasky 		lid_ho_2 =
801d6b92ffaSHans Petter Selasky 		    cl_ntoh16(osm_node_get_base_lid(p_node_2, port_num_2));
802d6b92ffaSHans Petter Selasky 
803d6b92ffaSHans Petter Selasky 	if (!lid_ho_1 || !lid_ho_2) {
804d6b92ffaSHans Petter Selasky 		/*
805d6b92ffaSHans Petter Selasky 		 * No lid assigned, which means that one of the nodes is new.
806d6b92ffaSHans Petter Selasky 		 * Need to wait for lid manager to process this node.
807d6b92ffaSHans Petter Selasky 		 * The switches and their links will be checked later when
808d6b92ffaSHans Petter Selasky 		 * the whole cache validity will be verified.
809d6b92ffaSHans Petter Selasky 		 */
810d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
811d6b92ffaSHans Petter Selasky 			"Link port %u <-> %u reveals new node - cache will "
812d6b92ffaSHans Petter Selasky 			"be validated later\n", port_num_1, port_num_2);
813d6b92ffaSHans Petter Selasky 		goto Exit;
814d6b92ffaSHans Petter Selasky 	}
815d6b92ffaSHans Petter Selasky 
816d6b92ffaSHans Petter Selasky 	cache_remove_port(p_mgr, lid_ho_1, port_num_1, lid_ho_2,
817d6b92ffaSHans Petter Selasky 			  (osm_node_get_type(p_node_2) !=
818d6b92ffaSHans Petter Selasky 			  IB_NODE_TYPE_SWITCH));
819d6b92ffaSHans Petter Selasky 
820d6b92ffaSHans Petter Selasky 	/* if node_2 is a switch, the link should be cleaned from its cache */
821d6b92ffaSHans Petter Selasky 
822d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH)
823d6b92ffaSHans Petter Selasky 		cache_remove_port(p_mgr, lid_ho_2,
824d6b92ffaSHans Petter Selasky 				  port_num_2, lid_ho_1, FALSE);
825d6b92ffaSHans Petter Selasky 
826d6b92ffaSHans Petter Selasky Exit:
827d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
828d6b92ffaSHans Petter Selasky }				/* osm_ucast_cache_check_new_link() */
829d6b92ffaSHans Petter Selasky 
osm_ucast_cache_add_link(osm_ucast_mgr_t * p_mgr,osm_physp_t * p_physp1,osm_physp_t * p_physp2)830d6b92ffaSHans Petter Selasky void osm_ucast_cache_add_link(osm_ucast_mgr_t * p_mgr,
831d6b92ffaSHans Petter Selasky 			      osm_physp_t * p_physp1, osm_physp_t * p_physp2)
832d6b92ffaSHans Petter Selasky {
833d6b92ffaSHans Petter Selasky 	osm_node_t *p_node_1 = p_physp1->p_node, *p_node_2 = p_physp2->p_node;
834d6b92ffaSHans Petter Selasky 	uint16_t lid_ho_1, lid_ho_2;
835d6b92ffaSHans Petter Selasky 
836d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
837d6b92ffaSHans Petter Selasky 
838d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
839d6b92ffaSHans Petter Selasky 		goto Exit;
840d6b92ffaSHans Petter Selasky 
841d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH &&
842d6b92ffaSHans Petter Selasky 	    osm_node_get_type(p_node_2) != IB_NODE_TYPE_SWITCH) {
843d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "Dropping CA-2-CA link\n");
844d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
845d6b92ffaSHans Petter Selasky 		goto Exit;
846d6b92ffaSHans Petter Selasky 	}
847d6b92ffaSHans Petter Selasky 
848d6b92ffaSHans Petter Selasky 	if ((osm_node_get_type(p_node_1) == IB_NODE_TYPE_SWITCH &&
849d6b92ffaSHans Petter Selasky 	     !osm_node_get_physp_ptr(p_node_1, 0)) ||
850d6b92ffaSHans Petter Selasky 	    (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH &&
851d6b92ffaSHans Petter Selasky 	     !osm_node_get_physp_ptr(p_node_2, 0))) {
852d6b92ffaSHans Petter Selasky 		/* we're caching a link when one of the nodes
853d6b92ffaSHans Petter Selasky 		   has already been dropped and cached */
854d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
855d6b92ffaSHans Petter Selasky 			"Port %u <-> port %u: port0 on one of the nodes "
856d6b92ffaSHans Petter Selasky 			"has already been dropped and cached\n",
857d6b92ffaSHans Petter Selasky 			p_physp1->port_num, p_physp2->port_num);
858d6b92ffaSHans Petter Selasky 		goto Exit;
859d6b92ffaSHans Petter Selasky 	}
860d6b92ffaSHans Petter Selasky 
861d6b92ffaSHans Petter Selasky 	/* One of the nodes is switch. Just for code
862d6b92ffaSHans Petter Selasky 	   simplicity, make sure that it's the first node. */
863d6b92ffaSHans Petter Selasky 
864d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH) {
865d6b92ffaSHans Petter Selasky 		osm_physp_t *tmp = p_physp1;
866d6b92ffaSHans Petter Selasky 		p_physp1 = p_physp2;
867d6b92ffaSHans Petter Selasky 		p_physp2 = tmp;
868d6b92ffaSHans Petter Selasky 		p_node_1 = p_physp1->p_node;
869d6b92ffaSHans Petter Selasky 		p_node_2 = p_physp2->p_node;
870d6b92ffaSHans Petter Selasky 	}
871d6b92ffaSHans Petter Selasky 
872d6b92ffaSHans Petter Selasky 	if (!p_node_1->sw) {
873d6b92ffaSHans Petter Selasky 		/* something is wrong - we'd better not use cache */
874d6b92ffaSHans Petter Selasky 		osm_ucast_cache_invalidate(p_mgr);
875d6b92ffaSHans Petter Selasky 		goto Exit;
876d6b92ffaSHans Petter Selasky 	}
877d6b92ffaSHans Petter Selasky 
878d6b92ffaSHans Petter Selasky 	lid_ho_1 = cl_ntoh16(osm_node_get_base_lid(p_node_1, 0));
879d6b92ffaSHans Petter Selasky 
880d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH) {
881d6b92ffaSHans Petter Selasky 
882d6b92ffaSHans Petter Selasky 		if (!p_node_2->sw) {
883d6b92ffaSHans Petter Selasky 			/* something is wrong - we'd better not use cache */
884d6b92ffaSHans Petter Selasky 			osm_ucast_cache_invalidate(p_mgr);
885d6b92ffaSHans Petter Selasky 			goto Exit;
886d6b92ffaSHans Petter Selasky 		}
887d6b92ffaSHans Petter Selasky 
888d6b92ffaSHans Petter Selasky 		lid_ho_2 = cl_ntoh16(osm_node_get_base_lid(p_node_2, 0));
889d6b92ffaSHans Petter Selasky 
890d6b92ffaSHans Petter Selasky 		/* lost switch-2-switch link - cache both sides */
891d6b92ffaSHans Petter Selasky 		cache_add_sw_link(p_mgr, p_physp1, lid_ho_2, FALSE);
892d6b92ffaSHans Petter Selasky 		cache_add_sw_link(p_mgr, p_physp2, lid_ho_1, FALSE);
893d6b92ffaSHans Petter Selasky 	} else {
894d6b92ffaSHans Petter Selasky 		lid_ho_2 = cl_ntoh16(osm_physp_get_base_lid(p_physp2));
895d6b92ffaSHans Petter Selasky 
896d6b92ffaSHans Petter Selasky 		/* lost link to CA/RTR - cache only switch side */
897d6b92ffaSHans Petter Selasky 		cache_add_sw_link(p_mgr, p_physp1, lid_ho_2, TRUE);
898d6b92ffaSHans Petter Selasky 	}
899d6b92ffaSHans Petter Selasky 
900d6b92ffaSHans Petter Selasky Exit:
901d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
902d6b92ffaSHans Petter Selasky }				/* osm_ucast_cache_add_link() */
903d6b92ffaSHans Petter Selasky 
osm_ucast_cache_add_node(osm_ucast_mgr_t * p_mgr,osm_node_t * p_node)904d6b92ffaSHans Petter Selasky void osm_ucast_cache_add_node(osm_ucast_mgr_t * p_mgr, osm_node_t * p_node)
905d6b92ffaSHans Petter Selasky {
906d6b92ffaSHans Petter Selasky 	uint16_t lid_ho;
907d6b92ffaSHans Petter Selasky 	uint8_t max_ports;
908d6b92ffaSHans Petter Selasky 	uint8_t port_num;
909d6b92ffaSHans Petter Selasky 	osm_physp_t *p_physp;
910d6b92ffaSHans Petter Selasky 	cache_switch_t *p_cache_sw;
911d6b92ffaSHans Petter Selasky 
912d6b92ffaSHans Petter Selasky 	OSM_LOG_ENTER(p_mgr->p_log);
913d6b92ffaSHans Petter Selasky 
914d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
915d6b92ffaSHans Petter Selasky 		goto Exit;
916d6b92ffaSHans Petter Selasky 
917d6b92ffaSHans Petter Selasky 	if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) {
918d6b92ffaSHans Petter Selasky 
919d6b92ffaSHans Petter Selasky 		lid_ho = cl_ntoh16(osm_node_get_base_lid(p_node, 0));
920d6b92ffaSHans Petter Selasky 
921d6b92ffaSHans Petter Selasky 		if (!lid_ho) {
922d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE,
923d6b92ffaSHans Petter Selasky 				"Skip caching. Switch dropped before "
924d6b92ffaSHans Petter Selasky 				"it gets a valid lid.\n");
925d6b92ffaSHans Petter Selasky 			osm_ucast_cache_invalidate(p_mgr);
926d6b92ffaSHans Petter Selasky 			goto Exit;
927d6b92ffaSHans Petter Selasky 		}
928d6b92ffaSHans Petter Selasky 
929d6b92ffaSHans Petter Selasky 		OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
930d6b92ffaSHans Petter Selasky 			"Caching dropped switch lid %u\n", lid_ho);
931d6b92ffaSHans Petter Selasky 
932d6b92ffaSHans Petter Selasky 		if (!p_node->sw) {
933d6b92ffaSHans Petter Selasky 			/* something is wrong - forget about cache */
934d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR,
935d6b92ffaSHans Petter Selasky 				"ERR AD03: no switch info for node lid %u - "
936d6b92ffaSHans Petter Selasky 				"clearing cache\n", lid_ho);
937d6b92ffaSHans Petter Selasky 			osm_ucast_cache_invalidate(p_mgr);
938d6b92ffaSHans Petter Selasky 			goto Exit;
939d6b92ffaSHans Petter Selasky 		}
940d6b92ffaSHans Petter Selasky 
941d6b92ffaSHans Petter Selasky 		/* unlink (add to cache) all the ports of this switch */
942d6b92ffaSHans Petter Selasky 		max_ports = osm_node_get_num_physp(p_node);
943d6b92ffaSHans Petter Selasky 		for (port_num = 1; port_num < max_ports; port_num++) {
944d6b92ffaSHans Petter Selasky 
945d6b92ffaSHans Petter Selasky 			p_physp = osm_node_get_physp_ptr(p_node, port_num);
946d6b92ffaSHans Petter Selasky 			if (!p_physp || !p_physp->p_remote_physp)
947d6b92ffaSHans Petter Selasky 				continue;
948d6b92ffaSHans Petter Selasky 
949d6b92ffaSHans Petter Selasky 			osm_ucast_cache_add_link(p_mgr, p_physp,
950d6b92ffaSHans Petter Selasky 						 p_physp->p_remote_physp);
951d6b92ffaSHans Petter Selasky 		}
952d6b92ffaSHans Petter Selasky 
953d6b92ffaSHans Petter Selasky 		/*
954d6b92ffaSHans Petter Selasky 		 * All the ports have been dropped (cached).
955d6b92ffaSHans Petter Selasky 		 * If one of the ports was connected to CA/RTR,
956d6b92ffaSHans Petter Selasky 		 * then the cached switch would be marked as leaf.
957d6b92ffaSHans Petter Selasky 		 * If it isn't, then the dropped switch isn't a leaf,
958d6b92ffaSHans Petter Selasky 		 * and cache can't handle it.
959d6b92ffaSHans Petter Selasky 		 */
960d6b92ffaSHans Petter Selasky 
961d6b92ffaSHans Petter Selasky 		p_cache_sw = cache_get_sw(p_mgr, lid_ho);
962d6b92ffaSHans Petter Selasky 
963d6b92ffaSHans Petter Selasky 		/* p_cache_sw could be NULL if it has no remote phys ports */
964d6b92ffaSHans Petter Selasky 		if (!p_cache_sw || !cache_sw_is_leaf(p_cache_sw)) {
965d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
966d6b92ffaSHans Petter Selasky 				"Dropped non-leaf switch (lid %u)\n", lid_ho);
967d6b92ffaSHans Petter Selasky 			osm_ucast_cache_invalidate(p_mgr);
968d6b92ffaSHans Petter Selasky 			goto Exit;
969d6b92ffaSHans Petter Selasky 		}
970d6b92ffaSHans Petter Selasky 
971d6b92ffaSHans Petter Selasky 		p_cache_sw->dropped = TRUE;
972d6b92ffaSHans Petter Selasky 
973d6b92ffaSHans Petter Selasky 		if (!p_node->sw->num_hops || !p_node->sw->hops) {
974d6b92ffaSHans Petter Selasky 			OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG,
975d6b92ffaSHans Petter Selasky 				"No LID matrices for switch lid %u\n", lid_ho);
976d6b92ffaSHans Petter Selasky 			osm_ucast_cache_invalidate(p_mgr);
977d6b92ffaSHans Petter Selasky 			goto Exit;
978d6b92ffaSHans Petter Selasky 		}
979d6b92ffaSHans Petter Selasky 
980d6b92ffaSHans Petter Selasky 		/* lid matrices */
981d6b92ffaSHans Petter Selasky 
982d6b92ffaSHans Petter Selasky 		p_cache_sw->num_hops = p_node->sw->num_hops;
983d6b92ffaSHans Petter Selasky 		p_node->sw->num_hops = 0;
984d6b92ffaSHans Petter Selasky 		p_cache_sw->hops = p_node->sw->hops;
985d6b92ffaSHans Petter Selasky 		p_node->sw->hops = NULL;
986d6b92ffaSHans Petter Selasky 
987d6b92ffaSHans Petter Selasky 		/* linear forwarding table */
988d6b92ffaSHans Petter Selasky 
989d6b92ffaSHans Petter Selasky 		if (p_node->sw->new_lft) {
990d6b92ffaSHans Petter Selasky 			/* LFT buffer exists - we use it, because
991d6b92ffaSHans Petter Selasky 			   it is more updated than the switch's LFT */
992d6b92ffaSHans Petter Selasky 			p_cache_sw->lft = p_node->sw->new_lft;
993d6b92ffaSHans Petter Selasky 			p_node->sw->new_lft = NULL;
994d6b92ffaSHans Petter Selasky 		} else {
995d6b92ffaSHans Petter Selasky 			/* no LFT buffer, so we use the switch's LFT */
996d6b92ffaSHans Petter Selasky 			p_cache_sw->lft = p_node->sw->lft;
997d6b92ffaSHans Petter Selasky 			p_node->sw->lft = NULL;
998d6b92ffaSHans Petter Selasky 			p_node->sw->lft_size = 0;
999d6b92ffaSHans Petter Selasky 		}
1000d6b92ffaSHans Petter Selasky 		p_cache_sw->max_lid_ho = p_node->sw->max_lid_ho;
1001d6b92ffaSHans Petter Selasky 	} else {
1002d6b92ffaSHans Petter Selasky 		/* dropping CA/RTR: add to cache all the ports of this node */
1003d6b92ffaSHans Petter Selasky 		max_ports = osm_node_get_num_physp(p_node);
1004d6b92ffaSHans Petter Selasky 		for (port_num = 1; port_num < max_ports; port_num++) {
1005d6b92ffaSHans Petter Selasky 
1006d6b92ffaSHans Petter Selasky 			p_physp = osm_node_get_physp_ptr(p_node, port_num);
1007d6b92ffaSHans Petter Selasky 			if (!p_physp || !p_physp->p_remote_physp)
1008d6b92ffaSHans Petter Selasky 				continue;
1009d6b92ffaSHans Petter Selasky 
1010d6b92ffaSHans Petter Selasky 			CL_ASSERT(osm_node_get_type
1011d6b92ffaSHans Petter Selasky 				  (p_physp->p_remote_physp->p_node) ==
1012d6b92ffaSHans Petter Selasky 				  IB_NODE_TYPE_SWITCH);
1013d6b92ffaSHans Petter Selasky 
1014d6b92ffaSHans Petter Selasky 			osm_ucast_cache_add_link(p_mgr,
1015d6b92ffaSHans Petter Selasky 						 p_physp->p_remote_physp,
1016d6b92ffaSHans Petter Selasky 						 p_physp);
1017d6b92ffaSHans Petter Selasky 		}
1018d6b92ffaSHans Petter Selasky 	}
1019d6b92ffaSHans Petter Selasky Exit:
1020d6b92ffaSHans Petter Selasky 	OSM_LOG_EXIT(p_mgr->p_log);
1021d6b92ffaSHans Petter Selasky }				/* osm_ucast_cache_add_node() */
1022d6b92ffaSHans Petter Selasky 
osm_ucast_cache_process(osm_ucast_mgr_t * p_mgr)1023d6b92ffaSHans Petter Selasky int osm_ucast_cache_process(osm_ucast_mgr_t * p_mgr)
1024d6b92ffaSHans Petter Selasky {
1025d6b92ffaSHans Petter Selasky 	cl_qmap_t *tbl = &p_mgr->p_subn->sw_guid_tbl;
1026d6b92ffaSHans Petter Selasky 	cl_map_item_t *item;
1027d6b92ffaSHans Petter Selasky 	osm_switch_t *p_sw;
1028d6b92ffaSHans Petter Selasky 	uint16_t lft_size;
1029d6b92ffaSHans Petter Selasky 
1030d6b92ffaSHans Petter Selasky 	if (!p_mgr->p_subn->opt.use_ucast_cache)
1031d6b92ffaSHans Petter Selasky 		return 1;
1032d6b92ffaSHans Petter Selasky 
1033d6b92ffaSHans Petter Selasky 	ucast_cache_validate(p_mgr);
1034d6b92ffaSHans Petter Selasky 	if (!p_mgr->cache_valid)
1035d6b92ffaSHans Petter Selasky 		return 1;
1036d6b92ffaSHans Petter Selasky 
1037d6b92ffaSHans Petter Selasky 	OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
1038d6b92ffaSHans Petter Selasky 		"Configuring switch tables using cached routing\n");
1039d6b92ffaSHans Petter Selasky 
1040d6b92ffaSHans Petter Selasky 	for (item = cl_qmap_head(tbl); item != cl_qmap_end(tbl);
1041d6b92ffaSHans Petter Selasky 	     item = cl_qmap_next(item)) {
1042d6b92ffaSHans Petter Selasky 		p_sw = (osm_switch_t *) item;
1043d6b92ffaSHans Petter Selasky 		CL_ASSERT(p_sw->new_lft);
1044d6b92ffaSHans Petter Selasky 		if (!p_sw->lft) {
1045d6b92ffaSHans Petter Selasky 			lft_size = (p_sw->max_lid_ho / IB_SMP_DATA_SIZE + 1)
1046d6b92ffaSHans Petter Selasky 				   * IB_SMP_DATA_SIZE;
1047d6b92ffaSHans Petter Selasky 			p_sw->lft = malloc(lft_size);
1048d6b92ffaSHans Petter Selasky 			if (!p_sw->lft)
1049d6b92ffaSHans Petter Selasky 				return IB_INSUFFICIENT_MEMORY;
1050d6b92ffaSHans Petter Selasky 			p_sw->lft_size = lft_size;
1051d6b92ffaSHans Petter Selasky 			memset(p_sw->lft, OSM_NO_PATH, p_sw->lft_size);
1052d6b92ffaSHans Petter Selasky 		}
1053d6b92ffaSHans Petter Selasky 
1054d6b92ffaSHans Petter Selasky 	}
1055d6b92ffaSHans Petter Selasky 
1056d6b92ffaSHans Petter Selasky 	osm_ucast_mgr_set_fwd_tables(p_mgr);
1057d6b92ffaSHans Petter Selasky 
1058d6b92ffaSHans Petter Selasky 	return 0;
1059d6b92ffaSHans Petter Selasky }
1060