xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rds/rdsib_sc.c (revision b86efd96f8acd85ddaa930a2f0c1d664237e4aaf)
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 2006 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[LIFNAMSIZ];
68 	char				rifname[LIFNAMSIZ];
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 /*
83  * Called by SC on discovering a new path
84  */
85 void
86 rds_path_up(rds_path_t *path)
87 {
88 	rds_node_record_t	*p;
89 	rds_path_record_t	*p1;
90 
91 	ASSERT(path != NULL);
92 
93 	/* don't care if it is not IPoIB interface */
94 	if ((bcmp(path->local.ifname, "ibd", 3) != 0) ||
95 	    (bcmp(path->remote.ifname, "ibd", 3) != 0)) {
96 		RDS_DPRINTF3("rds_path_up",
97 		    "(%s | %s) Not IPoIB interface, ignore",
98 		    path->local.ifname, path->remote.ifname);
99 		return;
100 	}
101 
102 	mutex_enter(&rds_pathmap_lock);
103 
104 	p = rds_pathmap;
105 	while ((p) && ((p->lnode_ip != path->local.node_ipaddr) ||
106 	    (p->rnode_ip != path->remote.node_ipaddr))) {
107 		p = p->nextp;
108 	}
109 
110 	if (p == NULL) {
111 		p = (rds_node_record_t *)kmem_alloc(sizeof (rds_node_record_t),
112 		    KM_SLEEP);
113 		p1 = (rds_path_record_t *)kmem_alloc(
114 		    sizeof (rds_path_record_t), KM_SLEEP);
115 
116 		p->nextp = NULL;
117 		p->lnode_ip = path->local.node_ipaddr;
118 		p->rnode_ip = path->remote.node_ipaddr;
119 		p->downp = p1;
120 		p->prevp = NULL;
121 
122 		p1->libd_ip = path->local.ipaddr;
123 		p1->ribd_ip = path->remote.ipaddr;
124 		p1->up = NULL;
125 		p1->downp = NULL;
126 		(void) strcpy(p1->lifname, path->local.ifname);
127 		(void) strcpy(p1->rifname, path->remote.ifname);
128 
129 		if (rds_pathmap == NULL) {
130 			rds_pathmap = p;
131 		} else {
132 			/* insert this node at the head */
133 			rds_pathmap->prevp = p;
134 			p->nextp = rds_pathmap;
135 			rds_pathmap = p;
136 		}
137 	} else {
138 		/* we found a match */
139 		p1 = (rds_path_record_t *)kmem_alloc(
140 		    sizeof (rds_path_record_t), KM_SLEEP);
141 
142 		p1->libd_ip = path->local.ipaddr;
143 		p1->ribd_ip = path->remote.ipaddr;
144 		p1->downp = p->downp;
145 		p->downp->up = p1;
146 		p1->up = NULL;
147 		p->downp = p1;
148 		(void) strcpy(p1->lifname, path->local.ifname);
149 		(void) strcpy(p1->rifname, path->remote.ifname);
150 	}
151 
152 	mutex_exit(&rds_pathmap_lock);
153 }
154 
155 /*
156  * Called by SC to delete a path
157  */
158 void
159 rds_path_down(rds_path_t *path)
160 {
161 	rds_node_record_t	*p;
162 	rds_path_record_t	*p1, *p1up, *p1downp;
163 
164 	ASSERT(path != NULL);
165 
166 	/* don't care if it is not IPoIB interface */
167 	if ((bcmp(path->local.ifname, "ibd", 3) != 0) ||
168 	    (bcmp(path->remote.ifname, "ibd", 3) != 0)) {
169 		RDS_DPRINTF3("rds_path_down",
170 		    "(%s | %s) Not IPoIB interface, ignore",
171 		    path->local.ifname, path->remote.ifname);
172 		return;
173 	}
174 
175 	mutex_enter(&rds_pathmap_lock);
176 
177 	p = rds_pathmap;
178 	while ((p) && ((p->lnode_ip != path->local.node_ipaddr) ||
179 	    (p->rnode_ip != path->remote.node_ipaddr))) {
180 		p = p->nextp;
181 	}
182 
183 	if (p == NULL) {
184 		/* no match */
185 		RDS_DPRINTF2("rds_path_down", "Node record not found "
186 		    "(0x%x <-> 0x%x)", path->local.node_ipaddr,
187 		    path->remote.node_ipaddr);
188 		mutex_exit(&rds_pathmap_lock);
189 		return;
190 	}
191 
192 	p1 = p->downp;
193 	while ((p1) && ((p1->libd_ip != path->local.ipaddr) ||
194 	    (p1->ribd_ip != path->remote.ipaddr))) {
195 		p1 = p1->downp;
196 	}
197 
198 	if (p1 == NULL) {
199 		/* no match */
200 		RDS_DPRINTF2("rds_path_down", "Path record not found "
201 		    "(0x%x <-> 0x%x)", path->local.ipaddr, path->remote.ipaddr);
202 		mutex_exit(&rds_pathmap_lock);
203 		return;
204 	}
205 
206 	/* we found the record, remove it */
207 	p1up = p1->up;
208 	p1downp = p1->downp;
209 
210 	if (p1up) {
211 		p1up->downp = p1downp;
212 	} else {
213 		/* this is the first path record */
214 		p->downp = p1downp;
215 	}
216 
217 	if (p1downp) {
218 		p1downp->up = p1up;
219 	}
220 
221 	kmem_free(p1, sizeof (rds_path_record_t));
222 
223 	/* remove the node record if there are no path records */
224 	if (p->downp == NULL) {
225 		if (p->prevp) {
226 			p->prevp->nextp = p->nextp;
227 		} else {
228 			/* this is the first node record */
229 			ASSERT(p == rds_pathmap);
230 			rds_pathmap = p;
231 		}
232 
233 		if (p->nextp) {
234 			p->nextp->prevp = p->prevp;
235 		}
236 
237 		kmem_free(p, sizeof (rds_node_record_t));
238 	}
239 
240 	mutex_exit(&rds_pathmap_lock);
241 }
242 
243 int
244 rds_sc_path_lookup(ipaddr_t *localip, ipaddr_t *remip)
245 {
246 	rds_node_record_t	*p;
247 	rds_path_record_t	*p1;
248 
249 	mutex_enter(&rds_pathmap_lock);
250 
251 	p = rds_pathmap;
252 	while ((p) && ((p->lnode_ip != *localip) || (p->rnode_ip != *remip))) {
253 		p = p->nextp;
254 	}
255 
256 	if (p == NULL) {
257 		/* no match */
258 		RDS_DPRINTF2("rds_sc_path_lookup", "Node record not found "
259 		    "(0x%x <-> 0x%x)", *localip, *remip);
260 		mutex_exit(&rds_pathmap_lock);
261 		return (0);
262 	}
263 
264 	/* found a path */
265 	p1 = p->downp;
266 	*localip = p1->libd_ip;
267 	*remip = p1->ribd_ip;
268 
269 	mutex_exit(&rds_pathmap_lock);
270 
271 	return (1);
272 }
273 
274 boolean_t
275 rds_if_lookup_by_name(char *if_name)
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 != NULL) {
284 		p1 = p->downp;
285 		while ((p1 != NULL) && strcmp(if_name, p1->lifname)) {
286 			p1 = p1->downp;
287 		}
288 
289 		/* we found a match */
290 		if (p1 != NULL)
291 			break;
292 		/* go to the next node record */
293 		p = p->nextp;
294 	}
295 
296 	mutex_exit(&rds_pathmap_lock);
297 
298 	if (p == NULL) {
299 		/* no match */
300 		RDS_DPRINTF2("rds_if_lookup_by_name",
301 		    "Interface: %s not found", if_name);
302 		return (B_FALSE);
303 	}
304 
305 	/* Found a matching node record */
306 	return (B_TRUE);
307 }
308 
309 boolean_t
310 rds_if_lookup_by_addr(ipaddr_t addr)
311 {
312 	rds_node_record_t	*p;
313 	rds_path_record_t	*p1;
314 
315 	mutex_enter(&rds_pathmap_lock);
316 
317 	p = rds_pathmap;
318 	while ((p) && (p->lnode_ip != addr)) {
319 		p1 = p->downp;
320 		while ((p1) && (p1->libd_ip != addr)) {
321 			p1 = p1->downp;
322 		}
323 
324 		/* we found a match */
325 		if (p1 != NULL)
326 			break;
327 
328 		/* go to the next node record */
329 		p = p->nextp;
330 	}
331 
332 	mutex_exit(&rds_pathmap_lock);
333 	if (p == NULL) {
334 		/* no match */
335 		RDS_DPRINTF2("rds_if_lookup_by_addr",
336 		    "Addr: 0x%x not found", addr);
337 		return (B_FALSE);
338 	}
339 
340 	/* Found a matching node record */
341 	return (B_TRUE);
342 }
343