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 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 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 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 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 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 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