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