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