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
rds_clif_name(char * name)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
rds_path_up(rds_path_t * path)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
rds_path_down(rds_path_t * path)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
rds_sc_path_lookup(ipaddr_t * localip,ipaddr_t * remip)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
rds_if_lookup_by_name(char * devname)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
rds_if_lookup_by_addr(ipaddr_t addr)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