xref: /freebsd/contrib/ofed/opensm/opensm/osm_node.c (revision 10ff414c)
1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35 
36 /*
37  * Abstract:
38  *    Implementation of osm_node_t.
39  * This object represents an Infiniband Node.
40  * This object is part of the opensm family of objects.
41  */
42 
43 #if HAVE_CONFIG_H
44 #  include <config.h>
45 #endif				/* HAVE_CONFIG_H */
46 
47 #include <stdlib.h>
48 #include <iba/ib_types.h>
49 #include <opensm/osm_file_ids.h>
50 #define FILE_ID OSM_FILE_NODE_C
51 #include <opensm/osm_node.h>
52 #include <opensm/osm_madw.h>
53 
54 void osm_node_init_physp(IN osm_node_t * p_node, uint8_t port_num,
55 			 IN const osm_madw_t * p_madw)
56 {
57 	ib_net64_t port_guid;
58 	ib_smp_t *p_smp;
59 	ib_node_info_t *p_ni;
60 
61 	p_smp = osm_madw_get_smp_ptr(p_madw);
62 
63 	p_ni = ib_smp_get_payload_ptr(p_smp);
64 	port_guid = p_ni->port_guid;
65 
66 	CL_ASSERT(port_num < p_node->physp_tbl_size);
67 
68 	osm_physp_init(&p_node->physp_table[port_num],
69 		       port_guid, port_num, p_node,
70 		       osm_madw_get_bind_handle(p_madw),
71 		       p_smp->hop_count, p_smp->initial_path);
72 }
73 
74 osm_node_t *osm_node_new(IN const osm_madw_t * p_madw)
75 {
76 	osm_node_t *p_node;
77 	ib_smp_t *p_smp;
78 	ib_node_info_t *p_ni;
79 	uint8_t i;
80 	uint32_t size;
81 
82 	p_smp = osm_madw_get_smp_ptr(p_madw);
83 	p_ni = ib_smp_get_payload_ptr(p_smp);
84 
85 	/*
86 	   The node object already contains one physical port object.
87 	   Therefore, subtract 1 from the number of physical ports
88 	   used by the switch.  This is not done for CA's since they
89 	   need to occupy 1 more physp than they physically have since
90 	   we still reserve room for a "port 0".
91 	 */
92 	size = p_ni->num_ports;
93 
94 	p_node = malloc(sizeof(*p_node) + sizeof(osm_physp_t) * size);
95 	if (!p_node)
96 		return NULL;
97 
98 	memset(p_node, 0, sizeof(*p_node) + sizeof(osm_physp_t) * size);
99 	p_node->node_info = *p_ni;
100 	p_node->physp_tbl_size = size + 1;
101 
102 	p_node->physp_discovered = malloc(sizeof(uint8_t) * p_node->physp_tbl_size);
103 	if (!p_node->physp_discovered) {
104 		free(p_node);
105 		return NULL;
106 	}
107 	memset(p_node->physp_discovered, 0, sizeof(uint8_t) * p_node->physp_tbl_size);
108 	/*
109 	   Construct Physical Port objects owned by this Node.
110 	   Then, initialize the Physical Port through with we
111 	   discovered this port.
112 	   For switches, all ports have the same GUID.
113 	   For CAs and routers, each port has a different GUID, so we only
114 	   know the GUID for the port that responded to our
115 	   Get(NodeInfo).
116 	 */
117 	for (i = 0; i < p_node->physp_tbl_size; i++)
118 		osm_physp_construct(&p_node->physp_table[i]);
119 
120 	if (p_ni->node_type == IB_NODE_TYPE_SWITCH)
121 		for (i = 0; i <= p_ni->num_ports; i++)
122 			osm_node_init_physp(p_node, i, p_madw);
123 	else
124 		osm_node_init_physp(p_node,
125 				    ib_node_info_get_local_port_num(p_ni),
126 				    p_madw);
127 	p_node->print_desc = strdup(OSM_NODE_DESC_UNKNOWN);
128 
129 	return p_node;
130 }
131 
132 static void node_destroy(IN osm_node_t * p_node)
133 {
134 	uint16_t i;
135 
136 	/*
137 	   Cleanup all physports
138 	 */
139 	for (i = 0; i < p_node->physp_tbl_size; i++)
140 		osm_physp_destroy(&p_node->physp_table[i]);
141 
142 	/* cleanup printable node_desc field */
143 	if (p_node->print_desc)
144 		free(p_node->print_desc);
145 
146 	/* cleanup physp_discovered array */
147 	free(p_node->physp_discovered);
148 }
149 
150 void osm_node_delete(IN OUT osm_node_t ** p_node)
151 {
152 	CL_ASSERT(p_node && *p_node);
153 	node_destroy(*p_node);
154 	free(*p_node);
155 	*p_node = NULL;
156 }
157 
158 void osm_node_link(IN osm_node_t * p_node, IN uint8_t port_num,
159 		   IN osm_node_t * p_remote_node, IN uint8_t remote_port_num)
160 {
161 	osm_physp_t *p_physp;
162 	osm_physp_t *p_remote_physp;
163 
164 	p_physp = osm_node_get_physp_ptr(p_node, port_num);
165 	p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
166 
167 	if (p_physp->p_remote_physp)
168 		p_physp->p_remote_physp->p_remote_physp = NULL;
169 	if (p_remote_physp->p_remote_physp)
170 		p_remote_physp->p_remote_physp->p_remote_physp = NULL;
171 
172 	osm_physp_link(p_physp, p_remote_physp);
173 }
174 
175 void osm_node_unlink(IN osm_node_t * p_node, IN uint8_t port_num,
176 		     IN osm_node_t * p_remote_node, IN uint8_t remote_port_num)
177 {
178 	osm_physp_t *p_physp;
179 	osm_physp_t *p_remote_physp;
180 
181 	CL_ASSERT(port_num < p_node->physp_tbl_size);
182 	CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
183 
184 	if (osm_node_link_exists(p_node, port_num,
185 				 p_remote_node, remote_port_num)) {
186 
187 		p_physp = osm_node_get_physp_ptr(p_node, port_num);
188 		p_remote_physp =
189 		    osm_node_get_physp_ptr(p_remote_node, remote_port_num);
190 
191 		osm_physp_unlink(p_physp, p_remote_physp);
192 	}
193 }
194 
195 boolean_t osm_node_link_exists(IN osm_node_t * p_node, IN uint8_t port_num,
196 			       IN osm_node_t * p_remote_node,
197 			       IN uint8_t remote_port_num)
198 {
199 	osm_physp_t *p_physp;
200 	osm_physp_t *p_remote_physp;
201 
202 	CL_ASSERT(port_num < p_node->physp_tbl_size);
203 	CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
204 
205 	p_physp = osm_node_get_physp_ptr(p_node, port_num);
206 	p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
207 
208 	return osm_physp_link_exists(p_physp, p_remote_physp);
209 }
210 
211 boolean_t osm_node_link_has_valid_ports(IN osm_node_t * p_node,
212 					IN uint8_t port_num,
213 					IN osm_node_t * p_remote_node,
214 					IN uint8_t remote_port_num)
215 {
216 	osm_physp_t *p_physp;
217 	osm_physp_t *p_remote_physp;
218 
219 	CL_ASSERT(port_num < p_node->physp_tbl_size);
220 	CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
221 
222 	p_physp = osm_node_get_physp_ptr(p_node, port_num);
223 	p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
224 
225 	return (p_physp && p_remote_physp);
226 }
227 
228 boolean_t osm_node_has_any_link(IN osm_node_t * p_node, IN uint8_t port_num)
229 {
230 	osm_physp_t *p_physp;
231 	CL_ASSERT(port_num < p_node->physp_tbl_size);
232 	p_physp = osm_node_get_physp_ptr(p_node, port_num);
233 	return osm_physp_has_any_link(p_physp);
234 }
235 
236 osm_node_t *osm_node_get_remote_node(IN osm_node_t * p_node,
237 				     IN uint8_t port_num,
238 				     OUT uint8_t * p_remote_port_num)
239 {
240 	osm_physp_t *p_physp;
241 	osm_physp_t *p_remote_physp;
242 
243 	p_physp = osm_node_get_physp_ptr(p_node, port_num);
244 
245 	if (!p_physp || !osm_physp_has_any_link(p_physp))
246 		return NULL;
247 
248 	p_remote_physp = osm_physp_get_remote(p_physp);
249 	if (p_remote_port_num)
250 		*p_remote_port_num = osm_physp_get_port_num(p_remote_physp);
251 
252 	return osm_physp_get_node_ptr(p_remote_physp);
253 }
254 
255 /**********************************************************************
256  The lock must be held before calling this function.
257 **********************************************************************/
258 ib_net16_t osm_node_get_remote_base_lid(IN osm_node_t * p_node,
259 					IN uint32_t port_num)
260 {
261 	osm_physp_t *p_physp;
262 	osm_physp_t *p_remote_physp;
263 	CL_ASSERT(port_num < p_node->physp_tbl_size);
264 
265 	p_physp = osm_node_get_physp_ptr(p_node, port_num);
266 	if (p_physp) {
267 		p_remote_physp = osm_physp_get_remote(p_physp);
268 		return osm_physp_get_base_lid(p_remote_physp);
269 	}
270 
271 	return 0;
272 }
273