xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rds/rdsib_sc.c (revision c1f8b08e52d9b30bd55daeac694e3a7f50d3cd21)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/ib/clients/rds/rdsib_sc.h>
29 #include <sys/ib/clients/rds/rdsib_debug.h>
30 #include <sys/types.h>
31 #include <sys/sunddi.h>
32 
33 /*
34  * RDS Path MAP
35  *
36  * N - Node record, P - Path record
37  *
38  * rds_path_map -
39  *              |
40  *              v
41  *      	---------	---------	---------
42  *     		|   N   |------>|  N    |------>|   N   |------> NULL
43  * NULL <-------|       |<------|       |<------|       |
44  *     		---------       ---------       ---------
45  *               |               |               |
46  *               |               |               |
47  *               v               v               v
48  *		--------        ---------       ---------
49  *		|  P   |        |  P    |       |  P    |
50  *		--------        ---------       ---------
51  *		|  ^            |   ^           |   ^
52  *		|  |            |   |           |   |
53  *		v  |            v   |           v   |
54  *		--------	--------	---------
55  *		|   P  |	|  P   |	|  P    |
56  *		--------	--------	---------
57  *		  o		   o		   o
58  *		  o		   o		   o
59  *		  o		   o		   o
60  */
61 
62 typedef struct rds_path_record_s {
63 	ipaddr_t			libd_ip;
64 	ipaddr_t			ribd_ip;
65 	struct rds_path_record_s	*up;
66 	struct rds_path_record_s	*downp;
67 	char				lifname[MAXNAMELEN];
68 	char				rifname[MAXNAMELEN];
69 } rds_path_record_t;
70 
71 typedef struct rds_node_record_s {
72 	struct rds_node_record_s	*nextp;
73 	ipaddr_t			lnode_ip;	/* local ip */
74 	ipaddr_t			rnode_ip;	/* remote ip */
75 	struct rds_path_record_s	*downp;
76 	struct rds_node_record_s	*prevp;
77 } rds_node_record_t;
78 
79 kmutex_t		rds_pathmap_lock;
80 rds_node_record_t	*rds_pathmap = NULL;
81 
82 static boolean_t
83 rds_validate_interface(rds_path_t *path)
84 {
85 	char			devname[MAXNAMELEN];
86 	uint_t			instance;
87 
88 	/* separate devname and instance number */
89 	if (ddi_parse(path->local.ifname, devname, &instance) != DDI_SUCCESS) {
90 		RDS_DPRINTF2("rds_validate_interface",
91 		    "local: %s is not right", path->local.ifname);
92 		return (B_FALSE);
93 	}
94 
95 	/* don't care if it is not IPoIB interface */
96 	if (strcmp(devname, "ibd") != 0) {
97 		RDS_DPRINTF2("rds_validate_interface",
98 		    "local: %s is not IB interface", devname);
99 		return (B_FALSE);
100 	}
101 
102 	/* separate devname and instance number */
103 	if (ddi_parse(path->remote.ifname, devname, &instance) != DDI_SUCCESS) {
104 		RDS_DPRINTF2("rds_validate_interface",
105 		    "remote: %s is not right", path->remote.ifname);
106 		return (B_FALSE);
107 	}
108 
109 	/* don't care if it is not IPoIB interface */
110 	if (strcmp(devname, "ibd") != 0) {
111 		RDS_DPRINTF2("rds_validate_interface",
112 		    "remote: %s is not IB interface", devname);
113 		return (B_FALSE);
114 	}
115 
116 	return (B_TRUE);
117 }
118 
119 /*
120  * Called by SC on discovering a new path
121  */
122 void
123 rds_path_up(rds_path_t *path)
124 {
125 	rds_node_record_t	*p;
126 	rds_path_record_t	*p1;
127 
128 	ASSERT(path != NULL);
129 
130 	/* don't care if it is not IPoIB interface */
131 	if (rds_validate_interface(path) == B_FALSE) {
132 		RDS_DPRINTF2("rds_path_up", "NOT IB interface");
133 		return;
134 	}
135 
136 	mutex_enter(&rds_pathmap_lock);
137 
138 	p = rds_pathmap;
139 	while ((p) && ((p->lnode_ip != path->local.node_ipaddr) ||
140 	    (p->rnode_ip != path->remote.node_ipaddr))) {
141 		p = p->nextp;
142 	}
143 
144 	if (p == NULL) {
145 		p = (rds_node_record_t *)kmem_alloc(sizeof (rds_node_record_t),
146 		    KM_SLEEP);
147 		p1 = (rds_path_record_t *)kmem_alloc(
148 		    sizeof (rds_path_record_t), KM_SLEEP);
149 
150 		p->nextp = NULL;
151 		p->lnode_ip = path->local.node_ipaddr;
152 		p->rnode_ip = path->remote.node_ipaddr;
153 		p->downp = p1;
154 		p->prevp = NULL;
155 
156 		p1->libd_ip = path->local.ipaddr;
157 		p1->ribd_ip = path->remote.ipaddr;
158 		p1->up = NULL;
159 		p1->downp = NULL;
160 		(void) strcpy(p1->lifname, path->local.ifname);
161 		(void) strcpy(p1->rifname, path->remote.ifname);
162 
163 		if (rds_pathmap == NULL) {
164 			rds_pathmap = p;
165 		} else {
166 			/* insert this node at the head */
167 			rds_pathmap->prevp = p;
168 			p->nextp = rds_pathmap;
169 			rds_pathmap = p;
170 		}
171 	} else {
172 		/* we found a match */
173 		p1 = (rds_path_record_t *)kmem_alloc(
174 		    sizeof (rds_path_record_t), KM_SLEEP);
175 
176 		p1->libd_ip = path->local.ipaddr;
177 		p1->ribd_ip = path->remote.ipaddr;
178 		p1->downp = p->downp;
179 		p->downp->up = p1;
180 		p1->up = NULL;
181 		p->downp = p1;
182 		(void) strcpy(p1->lifname, path->local.ifname);
183 		(void) strcpy(p1->rifname, path->remote.ifname);
184 	}
185 
186 	mutex_exit(&rds_pathmap_lock);
187 }
188 
189 /*
190  * Called by SC to delete a path
191  */
192 void
193 rds_path_down(rds_path_t *path)
194 {
195 	rds_node_record_t	*p;
196 	rds_path_record_t	*p1, *p1up, *p1downp;
197 
198 	ASSERT(path != NULL);
199 
200 	/* don't care if it is not IPoIB interface */
201 	if (rds_validate_interface(path) == B_FALSE) {
202 		RDS_DPRINTF2("rds_path_down", "NOT IB interface");
203 		return;
204 	}
205 
206 	mutex_enter(&rds_pathmap_lock);
207 
208 	p = rds_pathmap;
209 	while ((p) && ((p->lnode_ip != path->local.node_ipaddr) ||
210 	    (p->rnode_ip != path->remote.node_ipaddr))) {
211 		p = p->nextp;
212 	}
213 
214 	if (p == NULL) {
215 		/* no match */
216 		RDS_DPRINTF2("rds_path_down", "Node record not found "
217 		    "(0x%x <-> 0x%x)", path->local.node_ipaddr,
218 		    path->remote.node_ipaddr);
219 		mutex_exit(&rds_pathmap_lock);
220 		return;
221 	}
222 
223 	p1 = p->downp;
224 	while ((p1) && ((p1->libd_ip != path->local.ipaddr) ||
225 	    (p1->ribd_ip != path->remote.ipaddr))) {
226 		p1 = p1->downp;
227 	}
228 
229 	if (p1 == NULL) {
230 		/* no match */
231 		RDS_DPRINTF2("rds_path_down", "Path record not found "
232 		    "(0x%x <-> 0x%x)", path->local.ipaddr, path->remote.ipaddr);
233 		mutex_exit(&rds_pathmap_lock);
234 		return;
235 	}
236 
237 	/* we found the record, remove it */
238 	p1up = p1->up;
239 	p1downp = p1->downp;
240 
241 	if (p1up) {
242 		p1up->downp = p1downp;
243 	} else {
244 		/* this is the first path record */
245 		p->downp = p1downp;
246 	}
247 
248 	if (p1downp) {
249 		p1downp->up = p1up;
250 	}
251 
252 	kmem_free(p1, sizeof (rds_path_record_t));
253 
254 	/* remove the node record if there are no path records */
255 	if (p->downp == NULL) {
256 		if (p->prevp) {
257 			p->prevp->nextp = p->nextp;
258 		} else {
259 			/* this is the first node record */
260 			ASSERT(p == rds_pathmap);
261 			rds_pathmap = p->nextp;
262 		}
263 
264 		if (p->nextp) {
265 			p->nextp->prevp = p->prevp;
266 		}
267 
268 		kmem_free(p, sizeof (rds_node_record_t));
269 	}
270 
271 	mutex_exit(&rds_pathmap_lock);
272 }
273 
274 int
275 rds_sc_path_lookup(ipaddr_t *localip, ipaddr_t *remip)
276 {
277 	rds_node_record_t	*p;
278 	rds_path_record_t	*p1;
279 
280 	mutex_enter(&rds_pathmap_lock);
281 
282 	p = rds_pathmap;
283 	while ((p) && ((p->lnode_ip != *localip) || (p->rnode_ip != *remip))) {
284 		p = p->nextp;
285 	}
286 
287 	if (p == NULL) {
288 		/* no match */
289 		RDS_DPRINTF2("rds_sc_path_lookup", "Node record not found "
290 		    "(0x%x <-> 0x%x)", *localip, *remip);
291 		mutex_exit(&rds_pathmap_lock);
292 		return (0);
293 	}
294 
295 	/* found a path */
296 	p1 = p->downp;
297 	*localip = p1->libd_ip;
298 	*remip = p1->ribd_ip;
299 
300 	mutex_exit(&rds_pathmap_lock);
301 
302 	return (1);
303 }
304 
305 boolean_t
306 rds_if_lookup_by_name(char *if_name)
307 {
308 	rds_node_record_t	*p;
309 	rds_path_record_t	*p1;
310 	char			devname[MAXNAMELEN];
311 	uint_t			instance;
312 
313 	if (ddi_parse(if_name, devname, &instance) != DDI_SUCCESS) {
314 		RDS_DPRINTF2("rds_if_lookup_by_name",
315 		    "if_name: %s is not right", if_name);
316 		return (B_FALSE);
317 	}
318 
319 	mutex_enter(&rds_pathmap_lock);
320 
321 	if (rds_pathmap == NULL) {
322 		/* SC is not configured */
323 		RDS_DPRINTF2("rds_if_lookup_by_name", "Pathmap is NULL");
324 		mutex_exit(&rds_pathmap_lock);
325 		return (B_FALSE);
326 	}
327 
328 	/*
329 	 * Sun Cluster always names its interconnect virtual network interface
330 	 * as clprivnetx, so  return TRUE if there is atleast one node record
331 	 * and the interface name is clprivnet something.
332 	 */
333 	if (strcmp(devname, "clprivnet") == 0) {
334 		/* clprivnet address */
335 		mutex_exit(&rds_pathmap_lock);
336 		return (B_TRUE);
337 	}
338 
339 	p = rds_pathmap;
340 
341 	while (p != NULL) {
342 		p1 = p->downp;
343 		while ((p1 != NULL) && strcmp(if_name, p1->lifname)) {
344 			p1 = p1->downp;
345 		}
346 
347 		/* we found a match */
348 		if (p1 != NULL)
349 			break;
350 		/* go to the next node record */
351 		p = p->nextp;
352 	}
353 
354 	mutex_exit(&rds_pathmap_lock);
355 
356 	if (p == NULL) {
357 		/* no match */
358 		RDS_DPRINTF2("rds_if_lookup_by_name",
359 		    "Interface: %s not found", if_name);
360 		return (B_FALSE);
361 	}
362 
363 	/* Found a matching node record */
364 	return (B_TRUE);
365 }
366 
367 boolean_t
368 rds_if_lookup_by_addr(ipaddr_t addr)
369 {
370 	rds_node_record_t	*p;
371 	rds_path_record_t	*p1;
372 
373 	mutex_enter(&rds_pathmap_lock);
374 
375 	p = rds_pathmap;
376 	while ((p) && (p->lnode_ip != addr)) {
377 		p1 = p->downp;
378 		while ((p1) && (p1->libd_ip != addr)) {
379 			p1 = p1->downp;
380 		}
381 
382 		/* we found a match */
383 		if (p1 != NULL)
384 			break;
385 
386 		/* go to the next node record */
387 		p = p->nextp;
388 	}
389 
390 	mutex_exit(&rds_pathmap_lock);
391 	if (p == NULL) {
392 		/* no match */
393 		RDS_DPRINTF2("rds_if_lookup_by_addr",
394 		    "Addr: 0x%x not found", addr);
395 		return (B_FALSE);
396 	}
397 
398 	/* Found a matching node record */
399 	return (B_TRUE);
400 }
401