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