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