xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rds/rdsib_sc.c (revision 8257fab973a69800a3a3309e8af21fc1876d2df9)
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 #include <sys/dlpi.h>
33 
34 /*
35  * RDS Path MAP
36  *
37  * N - Node record, P - Path record
38  *
39  * rds_path_map -
40  *              |
41  *              v
42  *      	---------	---------	---------
43  *     		|   N   |------>|  N    |------>|   N   |------> NULL
44  * NULL <-------|       |<------|       |<------|       |
45  *     		---------       ---------       ---------
46  *               |               |               |
47  *               |               |               |
48  *               v               v               v
49  *		--------        ---------       ---------
50  *		|  P   |        |  P    |       |  P    |
51  *		--------        ---------       ---------
52  *		|  ^            |   ^           |   ^
53  *		|  |            |   |           |   |
54  *		v  |            v   |           v   |
55  *		--------	--------	---------
56  *		|   P  |	|  P   |	|  P    |
57  *		--------	--------	---------
58  *		  o		   o		   o
59  *		  o		   o		   o
60  *		  o		   o		   o
61  */
62 
63 typedef struct rds_path_record_s {
64 	ipaddr_t			libd_ip;
65 	ipaddr_t			ribd_ip;
66 	struct rds_path_record_s	*up;
67 	struct rds_path_record_s	*downp;
68 	char				lifname[MAXNAMELEN];
69 	char				rifname[MAXNAMELEN];
70 } rds_path_record_t;
71 
72 typedef struct rds_node_record_s {
73 	struct rds_node_record_s	*nextp;
74 	ipaddr_t			lnode_ip;	/* local ip */
75 	ipaddr_t			rnode_ip;	/* remote ip */
76 	struct rds_path_record_s	*downp;
77 	struct rds_node_record_s	*prevp;
78 } rds_node_record_t;
79 
80 char			sc_device_name[MAXNAMELEN] = "NotInitialized";
81 kmutex_t		rds_pathmap_lock;
82 rds_node_record_t	*rds_pathmap = NULL;
83 
84 #define	RDS_VALIDATE_PATH(p)						\
85 	if ((p->local.iftype != DL_IB) || (p->remote.iftype != DL_IB))	\
86 		return
87 
88 #define	isalpha(ch)	(((ch) >= 'a' && (ch) <= 'z') || \
89 			((ch) >= 'A' && (ch) <= 'Z'))
90 
91 /*
92  * Called by SC to register the Sun Cluster device name
93  */
94 void
95 rds_clif_name(char *name)
96 {
97 	int	i;
98 
99 	ASSERT(name != NULL);
100 
101 	mutex_enter(&rds_pathmap_lock);
102 
103 	/* extract the device name from the interface name */
104 	i = strlen(name) - 1;
105 	while ((i >= 0) && (!isalpha(name[i]))) i--;
106 	if (i >= 0) {
107 		(void) strncpy(sc_device_name, name, i + 1);
108 		sc_device_name[i + 1] = '\0';
109 	}
110 
111 	mutex_exit(&rds_pathmap_lock);
112 }
113 
114 /*
115  * Called by SC on discovering a new path
116  */
117 void
118 rds_path_up(rds_path_t *path)
119 {
120 	rds_node_record_t	*p;
121 	rds_path_record_t	*p1;
122 
123 	ASSERT(path != NULL);
124 
125 	/* ignore if the end points are not of type DL_IB */
126 	RDS_VALIDATE_PATH(path);
127 
128 	mutex_enter(&rds_pathmap_lock);
129 
130 	p = rds_pathmap;
131 	while ((p) && ((p->lnode_ip != path->local.node_ipaddr) ||
132 	    (p->rnode_ip != path->remote.node_ipaddr))) {
133 		p = p->nextp;
134 	}
135 
136 	if (p == NULL) {
137 		p = (rds_node_record_t *)kmem_alloc(sizeof (rds_node_record_t),
138 		    KM_SLEEP);
139 		p1 = (rds_path_record_t *)kmem_alloc(
140 		    sizeof (rds_path_record_t), KM_SLEEP);
141 
142 		p->nextp = NULL;
143 		p->lnode_ip = path->local.node_ipaddr;
144 		p->rnode_ip = path->remote.node_ipaddr;
145 		p->downp = p1;
146 		p->prevp = NULL;
147 
148 		p1->libd_ip = path->local.ipaddr;
149 		p1->ribd_ip = path->remote.ipaddr;
150 		p1->up = NULL;
151 		p1->downp = NULL;
152 		(void) strcpy(p1->lifname, path->local.ifname);
153 		(void) strcpy(p1->rifname, path->remote.ifname);
154 
155 		if (rds_pathmap == NULL) {
156 			rds_pathmap = p;
157 		} else {
158 			/* insert this node at the head */
159 			rds_pathmap->prevp = p;
160 			p->nextp = rds_pathmap;
161 			rds_pathmap = p;
162 		}
163 	} else {
164 		/* we found a match */
165 		p1 = (rds_path_record_t *)kmem_alloc(
166 		    sizeof (rds_path_record_t), KM_SLEEP);
167 
168 		p1->libd_ip = path->local.ipaddr;
169 		p1->ribd_ip = path->remote.ipaddr;
170 		p1->downp = p->downp;
171 		p->downp->up = p1;
172 		p1->up = NULL;
173 		p->downp = p1;
174 		(void) strcpy(p1->lifname, path->local.ifname);
175 		(void) strcpy(p1->rifname, path->remote.ifname);
176 	}
177 
178 	mutex_exit(&rds_pathmap_lock);
179 }
180 
181 /*
182  * Called by SC to delete a path
183  */
184 void
185 rds_path_down(rds_path_t *path)
186 {
187 	rds_node_record_t	*p;
188 	rds_path_record_t	*p1, *p1up, *p1downp;
189 
190 	ASSERT(path != NULL);
191 
192 	/* ignore if the end points are not of type DL_IB */
193 	RDS_VALIDATE_PATH(path);
194 
195 	mutex_enter(&rds_pathmap_lock);
196 
197 	p = rds_pathmap;
198 	while ((p) && ((p->lnode_ip != path->local.node_ipaddr) ||
199 	    (p->rnode_ip != path->remote.node_ipaddr))) {
200 		p = p->nextp;
201 	}
202 
203 	if (p == NULL) {
204 		/* no match */
205 		RDS_DPRINTF2("rds_path_down", "Node record not found "
206 		    "(0x%x <-> 0x%x)", path->local.node_ipaddr,
207 		    path->remote.node_ipaddr);
208 		mutex_exit(&rds_pathmap_lock);
209 		return;
210 	}
211 
212 	p1 = p->downp;
213 	while ((p1) && ((p1->libd_ip != path->local.ipaddr) ||
214 	    (p1->ribd_ip != path->remote.ipaddr))) {
215 		p1 = p1->downp;
216 	}
217 
218 	if (p1 == NULL) {
219 		/* no match */
220 		RDS_DPRINTF2("rds_path_down", "Path record not found "
221 		    "(0x%x <-> 0x%x)", path->local.ipaddr, path->remote.ipaddr);
222 		mutex_exit(&rds_pathmap_lock);
223 		return;
224 	}
225 
226 	/* we found the record, remove it */
227 	p1up = p1->up;
228 	p1downp = p1->downp;
229 
230 	if (p1up) {
231 		p1up->downp = p1downp;
232 	} else {
233 		/* this is the first path record */
234 		p->downp = p1downp;
235 	}
236 
237 	if (p1downp) {
238 		p1downp->up = p1up;
239 	}
240 
241 	kmem_free(p1, sizeof (rds_path_record_t));
242 
243 	/* remove the node record if there are no path records */
244 	if (p->downp == NULL) {
245 		if (p->prevp) {
246 			p->prevp->nextp = p->nextp;
247 		} else {
248 			/* this is the first node record */
249 			ASSERT(p == rds_pathmap);
250 			rds_pathmap = p->nextp;
251 		}
252 
253 		if (p->nextp) {
254 			p->nextp->prevp = p->prevp;
255 		}
256 
257 		kmem_free(p, sizeof (rds_node_record_t));
258 	}
259 
260 	mutex_exit(&rds_pathmap_lock);
261 }
262 
263 int
264 rds_sc_path_lookup(ipaddr_t *localip, ipaddr_t *remip)
265 {
266 	rds_node_record_t	*p;
267 	rds_path_record_t	*p1, *p1downp;
268 
269 	mutex_enter(&rds_pathmap_lock);
270 
271 	p = rds_pathmap;
272 	while ((p) && ((p->lnode_ip != *localip) || (p->rnode_ip != *remip))) {
273 		p = p->nextp;
274 	}
275 
276 	if (p == NULL) {
277 		/* no match */
278 		RDS_DPRINTF2("rds_sc_path_lookup", "Node record not found "
279 		    "(0x%x <-> 0x%x)", *localip, *remip);
280 		mutex_exit(&rds_pathmap_lock);
281 		return (0);
282 	}
283 
284 	/* found a path */
285 	p1 = p->downp;
286 	*localip = p1->libd_ip;
287 	*remip = p1->ribd_ip;
288 
289 	/*
290 	 * But next time, we want to use a different path record so move this
291 	 * path record to the end.
292 	 */
293 	p1downp = p1->downp;
294 	if (p1downp != NULL) {
295 		p->downp = p1downp;
296 		p1downp->up = NULL;
297 
298 		/* walk down to the last path record */
299 		while (p1downp->downp != NULL) {
300 			p1downp = p1downp->downp;
301 		}
302 
303 		/* Attach the first path record to the end */
304 		p1downp->downp = p1;
305 		p1->up = p1downp;
306 		p1->downp = NULL;
307 	}
308 
309 	mutex_exit(&rds_pathmap_lock);
310 
311 	return (1);
312 }
313 
314 boolean_t
315 rds_if_lookup_by_name(char *devname)
316 {
317 	mutex_enter(&rds_pathmap_lock);
318 
319 	/*
320 	 * Sun Cluster always names its interconnect virtual network interface
321 	 * as clprivnetx, so  return TRUE if there is atleast one node record
322 	 * and the interface name is clprivnet something.
323 	 */
324 	if (strcmp(devname, sc_device_name) == 0) {
325 		/* clprivnet address */
326 		mutex_exit(&rds_pathmap_lock);
327 		return (B_TRUE);
328 	}
329 
330 	mutex_exit(&rds_pathmap_lock);
331 	return (B_FALSE);
332 }
333 
334 boolean_t
335 rds_if_lookup_by_addr(ipaddr_t addr)
336 {
337 	rds_node_record_t	*p;
338 	rds_path_record_t	*p1;
339 
340 	mutex_enter(&rds_pathmap_lock);
341 
342 	p = rds_pathmap;
343 	while ((p) && (p->lnode_ip != addr)) {
344 		p1 = p->downp;
345 		while ((p1) && (p1->libd_ip != addr)) {
346 			p1 = p1->downp;
347 		}
348 
349 		/* we found a match */
350 		if (p1 != NULL)
351 			break;
352 
353 		/* go to the next node record */
354 		p = p->nextp;
355 	}
356 
357 	mutex_exit(&rds_pathmap_lock);
358 	if (p == NULL) {
359 		/* no match */
360 		RDS_DPRINTF2("rds_if_lookup_by_addr",
361 		    "Addr: 0x%x not found", addr);
362 		return (B_FALSE);
363 	}
364 
365 	/* Found a matching node record */
366 	return (B_TRUE);
367 }
368