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