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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/ddi.h> 28 #include <sys/sunddi.h> 29 #include <sys/stropts.h> 30 #include <sys/stream.h> 31 #include <sys/strsun.h> 32 #include <sys/strsubr.h> 33 #include <sys/socket.h> 34 #include <sys/stat.h> 35 #include <net/if_arp.h> 36 #include <net/if_types.h> 37 #include <sys/file.h> 38 #include <sys/sockio.h> 39 #include <sys/pathname.h> 40 #include <inet/arp.h> 41 #include <sys/modctl.h> 42 43 #include <sys/ib/mgt/ibcm/ibcm_arp.h> 44 45 #include <sys/kstr.h> 46 #include <sys/tiuser.h> 47 #include <sys/t_kuser.h> 48 49 extern char cmlog[]; 50 51 extern int ibcm_arp_pr_lookup(ibcm_arp_streams_t *ib_s, ibt_ip_addr_t *dst_addr, 52 ibt_ip_addr_t *src_addr, ibcm_arp_pr_comp_func_t func); 53 extern void ibcm_arp_pr_arp_ack(mblk_t *mp); 54 extern void ibcm_arp_prwqn_delete(ibcm_arp_prwqn_t *wqnp); 55 56 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", datab)) 57 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibt_ip_addr_s)) 58 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_ip_t)) 59 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_ibd_insts_t)) 60 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibcm_arp_prwqn_t)) 61 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", iocblk)) 62 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", msgb)) 63 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", queue)) 64 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", sockaddr_in)) 65 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", sockaddr_in6)) 66 67 int ibcm_printip = 0; 68 69 /* 70 * Function: 71 * ibcm_ip_print 72 * Input: 73 * label Arbitrary qualifying string 74 * ipa Pointer to IP Address to print 75 */ 76 void 77 ibcm_ip_print(char *label, ibt_ip_addr_t *ipaddr) 78 { 79 char buf[INET6_ADDRSTRLEN]; 80 81 if (ipaddr->family == AF_INET) { 82 IBTF_DPRINTF_L2(cmlog, "%s: %s", label, 83 inet_ntop(AF_INET, &ipaddr->un.ip4addr, buf, sizeof (buf))); 84 } else if (ipaddr->family == AF_INET6) { 85 IBTF_DPRINTF_L2(cmlog, "%s: %s", label, inet_ntop(AF_INET6, 86 &ipaddr->un.ip6addr, buf, sizeof (buf))); 87 } else { 88 IBTF_DPRINTF_L2(cmlog, "%s: IP ADDR NOT SPECIFIED ", label); 89 } 90 } 91 92 /* 93 * ibcm_arp_get_ibaddr_cb 94 */ 95 static int 96 ibcm_arp_get_ibaddr_cb(void *arg, int status) 97 { 98 ibcm_arp_prwqn_t *wqnp = (ibcm_arp_prwqn_t *)arg; 99 ibcm_arp_streams_t *ib_s = (ibcm_arp_streams_t *)wqnp->arg; 100 101 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr_cb(ib_s: %p wqnp: %p)", 102 ib_s, wqnp); 103 104 mutex_enter(&ib_s->lock); 105 ib_s->status = status; 106 ib_s->done = B_TRUE; 107 108 IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr_cb: SGID %llX:%llX " 109 "DGID: %llX:%llX", wqnp->sgid.gid_prefix, wqnp->sgid.gid_guid, 110 wqnp->dgid.gid_prefix, wqnp->dgid.gid_guid); 111 112 /* lock is held by the caller. */ 113 cv_signal(&ib_s->cv); 114 mutex_exit(&ib_s->lock); 115 return (0); 116 } 117 118 /* 119 * Lower read service procedure (messages coming back from arp/ip). 120 * Process messages based on queue type. 121 */ 122 static int 123 ibcm_arp_lrsrv(queue_t *q) 124 { 125 mblk_t *mp; 126 ibcm_arp_streams_t *ib_s = q->q_ptr; 127 128 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lrsrv(%p, ibd_s: 0x%p)", q, ib_s); 129 130 if (WR(q) == ib_s->arpqueue) { 131 while (mp = getq(q)) { 132 ibcm_arp_pr_arp_ack(mp); 133 } 134 } 135 136 return (0); 137 } 138 139 /* 140 * Lower write service procedure. 141 * Used when lower streams are flow controlled. 142 */ 143 static int 144 ibcm_arp_lwsrv(queue_t *q) 145 { 146 mblk_t *mp; 147 148 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lwsrv(%p)", q); 149 150 while (mp = getq(q)) { 151 if (canputnext(q)) { 152 putnext(q, mp); 153 } else { 154 (void) putbq(q, mp); 155 qenable(q); 156 break; 157 } 158 } 159 160 return (0); 161 } 162 163 /* 164 * Lower read put procedure. Arp/ip messages come here. 165 */ 166 static int 167 ibcm_arp_lrput(queue_t *q, mblk_t *mp) 168 { 169 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_lrput(0x%p, db_type: %d)", 170 q, DB_TYPE(mp)); 171 172 switch (DB_TYPE(mp)) { 173 case M_FLUSH: 174 /* 175 * Turn around 176 */ 177 if (*mp->b_rptr & FLUSHW) { 178 *mp->b_rptr &= ~FLUSHR; 179 qreply(q, mp); 180 return (0); 181 } 182 freemsg(mp); 183 break; 184 case M_IOCACK: 185 case M_IOCNAK: 186 case M_DATA: 187 /* 188 * This could be in interrupt context. 189 * Some of the ibt calls cannot be called in 190 * interrupt context, so 191 * put it in the queue and the message will be 192 * processed by service proccedure 193 */ 194 (void) putq(q, mp); 195 qenable(q); 196 break; 197 default: 198 IBTF_DPRINTF_L2(cmlog, "ibcm_arp_lrput: " 199 "got unknown msg <0x%x>\n", mp->b_datap->db_type); 200 ASSERT(0); 201 break; 202 } 203 204 return (0); 205 } 206 207 /* 208 * Streams write queue module info 209 */ 210 static struct module_info ibcm_arp_winfo = { 211 0, /* module ID number */ 212 "ibcm", /* module name */ 213 0, /* min packet size */ 214 INFPSZ, 215 49152, /* STREAM queue high water mark -- 49152 */ 216 12 /* STREAM queue low water mark -- 12 */ 217 }; 218 219 /* 220 * Streams lower write queue, for ibcm/ip requests. 221 */ 222 static struct qinit ibcm_arp_lwinit = { 223 NULL, /* qi_putp */ 224 ibcm_arp_lwsrv, /* qi_srvp */ 225 NULL, /* qi_qopen */ 226 NULL, /* qi_qclose */ 227 NULL, /* qi_qadmin */ 228 &ibcm_arp_winfo, /* module info */ 229 NULL, /* module statistics struct */ 230 NULL, 231 NULL, 232 STRUIOT_NONE /* stream uio type is standard uiomove() */ 233 }; 234 235 /* 236 * Streams lower read queue: read reply messages from ibcm/ip. 237 */ 238 static struct qinit ibcm_arp_lrinit = { 239 ibcm_arp_lrput, /* qi_putp */ 240 ibcm_arp_lrsrv, /* qi_srvp */ 241 NULL, /* qi_qopen */ 242 NULL, /* qi_qclose */ 243 NULL, /* qi_qadmin */ 244 &ibcm_arp_winfo, /* module info */ 245 NULL, /* module statistics struct */ 246 NULL, 247 NULL, 248 STRUIOT_NONE /* stream uio type is standard uiomove() */ 249 }; 250 251 252 static int 253 ibcm_arp_link_driver(ibcm_arp_streams_t *ib_s, char *path, queue_t **q, 254 vnode_t **dev_vp) 255 { 256 struct stdata *dev_stp; 257 vnode_t *vp; 258 int error; 259 queue_t *rq; 260 261 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_link_driver: Enter: %s", path); 262 263 /* open the driver from inside the kernel */ 264 error = vn_open(path, UIO_SYSSPACE, FREAD|FWRITE, 0, &vp, 265 0, NULL); 266 if (error) { 267 IBTF_DPRINTF_L2(cmlog, "ibcm_arp_link_driver: " 268 "vn_open('%s') failed\n", path); 269 return (error); 270 } 271 *dev_vp = vp; 272 273 dev_stp = vp->v_stream; 274 *q = dev_stp->sd_wrq; 275 276 VN_HOLD(vp); 277 278 rq = RD(dev_stp->sd_wrq); 279 RD(rq)->q_ptr = WR(rq)->q_ptr = ib_s; 280 setq(rq, &ibcm_arp_lrinit, &ibcm_arp_lwinit, NULL, QMTSAFE, 281 SQ_CI|SQ_CO, B_FALSE); 282 283 return (0); 284 } 285 286 extern struct qinit strdata; 287 extern struct qinit stwdata; 288 289 /* 290 * Unlink ip, ibcm, icmp6 drivers 291 */ 292 /* ARGSUSED */ 293 static int 294 ibcm_arp_unlink_driver(queue_t **q, vnode_t **dev_vp) 295 { 296 vnode_t *vp = *dev_vp; 297 struct stdata *dev_stp = vp->v_stream; 298 queue_t *wrq, *rq; 299 int rc; 300 301 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_unlink_driver: Enter: 0x%p", q); 302 303 wrq = dev_stp->sd_wrq; 304 rq = RD(wrq); 305 306 disable_svc(rq); 307 wait_svc(rq); 308 flushq(rq, FLUSHALL); 309 flushq(WR(rq), FLUSHALL); 310 311 rq->q_ptr = wrq->q_ptr = dev_stp; 312 313 setq(rq, &strdata, &stwdata, NULL, QMTSAFE, SQ_CI|SQ_CO, B_TRUE); 314 315 if ((rc = VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL)) != 0) { 316 IBTF_DPRINTF_L2(cmlog, "ibcm_arp_unlink_driver: VOP_CLOSE " 317 "failed %d\n", rc); 318 } 319 VN_RELE(vp); 320 321 return (0); 322 } 323 324 static int 325 ibcm_arp_unlink_drivers(ibcm_arp_streams_t *ib_s) 326 { 327 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_unlink_drivers(%p)", ib_s); 328 329 if (ib_s->arpqueue) { 330 (void) ibcm_arp_unlink_driver(&ib_s->arpqueue, &ib_s->arp_vp); 331 } 332 333 return (0); 334 } 335 336 /* 337 * Link ip, ibtl drivers below ibtl 338 */ 339 static int 340 ibcm_arp_link_drivers(ibcm_arp_streams_t *ib_s) 341 { 342 int rc; 343 344 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_link_drivers(%p)", ib_s); 345 346 if ((rc = ibcm_arp_link_driver(ib_s, "/dev/arp", &ib_s->arpqueue, 347 &ib_s->arp_vp)) != 0) { 348 IBTF_DPRINTF_L2(cmlog, "ibcm_arp_link_drivers: " 349 "ibcm_arp_link_driver failed: %d\n", rc); 350 return (rc); 351 } 352 353 return (0); 354 } 355 356 ibt_status_t 357 ibcm_arp_get_ibaddr(ibt_ip_addr_t srcaddr, ibt_ip_addr_t destaddr, 358 ib_gid_t *sgid, ib_gid_t *dgid) 359 { 360 ibcm_arp_streams_t *ib_s; 361 ibcm_arp_prwqn_t *wqnp; 362 int ret = 0; 363 364 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr(%p, %p, %p, %p)", 365 srcaddr, destaddr, sgid, dgid); 366 367 ib_s = (ibcm_arp_streams_t *)kmem_zalloc(sizeof (ibcm_arp_streams_t), 368 KM_SLEEP); 369 370 mutex_init(&ib_s->lock, NULL, MUTEX_DEFAULT, NULL); 371 cv_init(&ib_s->cv, NULL, CV_DRIVER, NULL); 372 373 ret = ibcm_arp_link_drivers(ib_s); 374 if (ret != 0) { 375 IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: " 376 "ibcm_arp_link_drivers failed %d", ret); 377 goto arp_ibaddr_error; 378 } 379 380 mutex_enter(&ib_s->lock); 381 ib_s->done = B_FALSE; 382 mutex_exit(&ib_s->lock); 383 384 ret = ibcm_arp_pr_lookup(ib_s, &destaddr, &srcaddr, 385 ibcm_arp_get_ibaddr_cb); 386 387 IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibaddr: ibcm_arp_pr_lookup " 388 "returned: %d", ret); 389 if (ret == 0) { 390 mutex_enter(&ib_s->lock); 391 while (ib_s->done != B_TRUE) 392 cv_wait(&ib_s->cv, &ib_s->lock); 393 mutex_exit(&ib_s->lock); 394 } 395 396 (void) ibcm_arp_unlink_drivers(ib_s); 397 mutex_enter(&ib_s->lock); 398 wqnp = ib_s->wqnp; 399 if (ib_s->status == 0) { 400 if (sgid) 401 *sgid = ib_s->wqnp->sgid; 402 if (dgid) 403 *dgid = ib_s->wqnp->dgid; 404 405 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibaddr: SGID: %llX:%llX" 406 " DGID: %llX:%llX", 407 ib_s->wqnp->sgid.gid_prefix, ib_s->wqnp->sgid.gid_guid, 408 ib_s->wqnp->dgid.gid_prefix, ib_s->wqnp->dgid.gid_guid); 409 410 ibcm_arp_prwqn_delete(wqnp); 411 } else if (ret == 0) { 412 /* 413 * We come here only when lookup has returned empty (failed) 414 * via callback routine - ibcm_arp_get_ibaddr_cb 415 * i.e. ib_s->status is non-zero, while ret is zero. 416 */ 417 if (wqnp) 418 kmem_free(wqnp, sizeof (ibcm_arp_prwqn_t)); 419 } 420 ret = ib_s->status; 421 mutex_exit(&ib_s->lock); 422 423 arp_ibaddr_error: 424 425 mutex_destroy(&ib_s->lock); 426 cv_destroy(&ib_s->cv); 427 kmem_free(ib_s, sizeof (ibcm_arp_streams_t)); 428 429 if (ret) 430 return (IBT_FAILURE); 431 else 432 return (IBT_SUCCESS); 433 } 434 435 436 /* 437 * Routine to get list of "local" IP-ADDR to GID/P_KEY mapping information. 438 * Optionally, if "gid" and/or "p_key" info are specified, then retrieve the 439 * IP-ADDR info for that attribute only. 440 */ 441 442 static ibcm_arp_ip_t * 443 ibcm_arp_ibd_gid2mac(ib_gid_t *gid, ib_pkey_t pkey, ibcm_arp_ibd_insts_t *ibdp) 444 { 445 ibcm_arp_ip_t *ipp; 446 int i; 447 448 for (i = 0, ipp = ibdp->ibcm_arp_ip; i < ibdp->ibcm_arp_ibd_cnt; 449 i++, ipp++) { 450 if ((ipp->ip_port_gid.gid_prefix == gid->gid_prefix) && 451 (ipp->ip_port_gid.gid_guid == gid->gid_guid)) { 452 if (pkey) { 453 if (ipp->ip_pkey == pkey) 454 return (ipp); 455 else 456 continue; 457 } 458 return (ipp); 459 } 460 } 461 return (NULL); 462 } 463 464 static ibt_status_t 465 ibcm_arp_ibd_mac2gid(ibcm_arp_ibd_insts_t *ibdp, ibt_ip_addr_t *srcip, 466 ib_gid_t *sgid) 467 { 468 ibcm_arp_ip_t *ipp; 469 int i; 470 boolean_t found = B_FALSE; 471 472 for (i = 0, ipp = ibdp->ibcm_arp_ip; i < ibdp->ibcm_arp_ibd_cnt; 473 i++, ipp++) { 474 475 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_ibd_mac2gid: GID %llX:%llX", 476 ipp->ip_port_gid.gid_prefix, ipp->ip_port_gid.gid_guid); 477 478 if (srcip->family == ipp->ip_inet_family) { 479 if ((srcip->family == AF_INET) && 480 (bcmp(&srcip->un.ip4addr, &ipp->ip_cm_sin.sin_addr, 481 sizeof (in_addr_t)) == 0)) { 482 found = B_TRUE; 483 } else if ((srcip->family == AF_INET6) && 484 IN6_ARE_ADDR_EQUAL(&srcip->un.ip6addr, 485 &ipp->ip_cm_sin6.sin6_addr)) { 486 found = B_TRUE; 487 } 488 if (found) { 489 *sgid = ipp->ip_port_gid; 490 491 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_ibd_mac2gid: " 492 "Found GID %llX:%llX", sgid->gid_prefix, 493 sgid->gid_guid); 494 return (IBT_SUCCESS); 495 } 496 } else { 497 IBTF_DPRINTF_L3(cmlog, "ibcm_arp_ibd_mac2gid: Different" 498 " family keep searching..."); 499 } 500 } 501 IBTF_DPRINTF_L3(cmlog, "ibcm_arp_ibd_mac2gid: Matching SRC info " 502 "NOT Found"); 503 return (IBT_SRC_IP_NOT_FOUND); 504 } 505 506 static int 507 ibcm_arp_get_ibd_insts_cb(dev_info_t *dip, void *arg) 508 { 509 ibcm_arp_ibd_insts_t *ibds = (ibcm_arp_ibd_insts_t *)arg; 510 ibcm_arp_ip_t *ipp; 511 ib_pkey_t pkey; 512 uint8_t port; 513 ib_guid_t hca_guid; 514 ib_gid_t port_gid; 515 516 if (i_ddi_devi_attached(dip) && 517 (strcmp(ddi_node_name(dip), "ibport") == 0) && 518 (strstr(ddi_get_name_addr(dip), "ipib") != NULL)) { 519 520 if (ibds->ibcm_arp_ibd_cnt >= ibds->ibcm_arp_ibd_alloc) { 521 ibcm_arp_ip_t *tmp = NULL; 522 uint8_t new_count; 523 524 new_count = ibds->ibcm_arp_ibd_alloc + 525 IBCM_ARP_IBD_INSTANCES; 526 527 tmp = (ibcm_arp_ip_t *)kmem_zalloc( 528 new_count * sizeof (ibcm_arp_ip_t), KM_SLEEP); 529 bcopy(ibds->ibcm_arp_ip, tmp, 530 ibds->ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t)); 531 kmem_free(ibds->ibcm_arp_ip, 532 ibds->ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t)); 533 ibds->ibcm_arp_ibd_alloc = new_count; 534 ibds->ibcm_arp_ip = tmp; 535 } 536 537 if (((hca_guid = ddi_prop_get_int64(DDI_DEV_T_ANY, dip, 0, 538 "hca-guid", 0)) == 0) || 539 ((port = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 540 "port-number", 0)) == 0) || 541 (ibt_get_port_state_byguid(hca_guid, port, &port_gid, 542 NULL) != IBT_SUCCESS) || 543 ((pkey = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 544 "port-pkey", IB_PKEY_INVALID_LIMITED)) <= 545 IB_PKEY_INVALID_FULL)) { 546 return (DDI_WALK_CONTINUE); 547 } 548 549 ipp = &ibds->ibcm_arp_ip[ibds->ibcm_arp_ibd_cnt]; 550 ipp->ip_inst = ddi_get_instance(dip); 551 ipp->ip_pkey = pkey; 552 ipp->ip_hca_guid = hca_guid; 553 ipp->ip_port_gid = port_gid; 554 ibds->ibcm_arp_ibd_cnt++; 555 } 556 return (DDI_WALK_CONTINUE); 557 } 558 559 static void 560 ibcm_arp_get_ibd_insts(ibcm_arp_ibd_insts_t *ibds) 561 { 562 ddi_walk_devs(ddi_root_node(), ibcm_arp_get_ibd_insts_cb, ibds); 563 } 564 565 /* 566 * Issue an ioctl down to IP. There are several similar versions of this 567 * function (e.g., rpcib_do_ip_ioctl()); clearly a utility routine is needed. 568 */ 569 static int 570 ibcm_do_ip_ioctl(int cmd, int len, void *arg) 571 { 572 vnode_t *kvp; 573 TIUSER *tiptr; 574 struct strioctl iocb; 575 int err = 0; 576 577 if (lookupname("/dev/udp", UIO_SYSSPACE, FOLLOW, NULLVPP, &kvp) != 0) 578 return (EPROTO); 579 580 if (t_kopen(NULL, kvp->v_rdev, FREAD|FWRITE, &tiptr, CRED()) != 0) { 581 VN_RELE(kvp); 582 return (EPROTO); 583 } 584 585 iocb.ic_cmd = cmd; 586 iocb.ic_timout = 0; 587 iocb.ic_len = len; 588 iocb.ic_dp = (caddr_t)arg; 589 err = kstr_ioctl(tiptr->fp->f_vnode, I_STR, (intptr_t)&iocb); 590 (void) t_kclose(tiptr, 0); 591 VN_RELE(kvp); 592 return (err); 593 } 594 595 /* 596 * Issue an SIOCGLIFCONF down to IP and return the result in `lifcp'. 597 * lifcp->lifc_buf is dynamically allocated to be *bufsizep bytes. 598 */ 599 static int 600 ibcm_do_lifconf(struct lifconf *lifcp, uint_t *bufsizep, sa_family_t family_loc) 601 { 602 int err; 603 struct lifnum lifn; 604 605 bzero(&lifn, sizeof (struct lifnum)); 606 lifn.lifn_family = family_loc; 607 608 err = ibcm_do_ip_ioctl(SIOCGLIFNUM, sizeof (struct lifnum), &lifn); 609 if (err != 0) 610 return (err); 611 612 IBTF_DPRINTF_L4(cmlog, "ibcm_do_lifconf: Family %d, lifn_count %d", 613 family_loc, lifn.lifn_count); 614 /* 615 * Pad the interface count to account for additional interfaces that 616 * may have been configured between the SIOCGLIFNUM and SIOCGLIFCONF. 617 */ 618 lifn.lifn_count += 4; 619 620 bzero(lifcp, sizeof (struct lifconf)); 621 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lifcp)) 622 lifcp->lifc_family = family_loc; 623 lifcp->lifc_len = *bufsizep = lifn.lifn_count * sizeof (struct lifreq); 624 lifcp->lifc_buf = kmem_zalloc(*bufsizep, KM_SLEEP); 625 626 err = ibcm_do_ip_ioctl(SIOCGLIFCONF, sizeof (struct lifconf), lifcp); 627 if (err != 0) { 628 kmem_free(lifcp->lifc_buf, *bufsizep); 629 return (err); 630 } 631 return (0); 632 } 633 634 /* 635 * Fill in `ibds' with IP addresses tied to IFT_IB IP interfaces. Returns 636 * B_TRUE if at least one address was filled in. 637 */ 638 static boolean_t 639 ibcm_arp_get_ibd_ipaddr(ibcm_arp_ibd_insts_t *ibds, sa_family_t family_loc) 640 { 641 int i, nifs, naddr = 0; 642 uint_t bufsize; 643 struct lifconf lifc; 644 struct lifreq *lifrp; 645 ibcm_arp_ip_t *ipp; 646 647 if (ibcm_do_lifconf(&lifc, &bufsize, family_loc) != 0) 648 return (B_FALSE); 649 650 nifs = lifc.lifc_len / sizeof (struct lifreq); 651 652 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibd_ipaddr: Family %d, nifs %d", 653 family_loc, nifs); 654 655 for (lifrp = lifc.lifc_req, i = 0; 656 i < nifs && naddr < ibds->ibcm_arp_ibd_cnt; i++, lifrp++) { 657 if (lifrp->lifr_type != IFT_IB) 658 continue; 659 660 ipp = &ibds->ibcm_arp_ip[naddr]; 661 switch (lifrp->lifr_addr.ss_family) { 662 case AF_INET: 663 ipp->ip_inet_family = AF_INET; 664 bcopy(&lifrp->lifr_addr, &ipp->ip_cm_sin, 665 sizeof (struct sockaddr_in)); 666 naddr++; 667 break; 668 case AF_INET6: 669 ipp->ip_inet_family = AF_INET6; 670 bcopy(&lifrp->lifr_addr, &ipp->ip_cm_sin6, 671 sizeof (struct sockaddr_in6)); 672 naddr++; 673 break; 674 } 675 } 676 677 kmem_free(lifc.lifc_buf, bufsize); 678 return (naddr > 0); 679 } 680 681 ibt_status_t 682 ibcm_arp_get_ibds(ibcm_arp_ibd_insts_t *ibdp, sa_family_t family_loc) 683 { 684 #ifdef DEBUG 685 int i; 686 #endif 687 688 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds(%p)", ibdp); 689 690 ibcm_arp_get_ibd_insts(ibdp); 691 692 IBTF_DPRINTF_L3(cmlog, "ibcm_arp_get_ibds: Found %d ibd instances", 693 ibdp->ibcm_arp_ibd_cnt); 694 695 if (ibdp->ibcm_arp_ibd_cnt == 0) 696 return (IBT_SRC_IP_NOT_FOUND); 697 698 /* Get the IP addresses of active ports. */ 699 if (!ibcm_arp_get_ibd_ipaddr(ibdp, family_loc)) { 700 IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_ibds: failed to get " 701 "ibd instance: IBT_SRC_IP_NOT_FOUND"); 702 return (IBT_SRC_IP_NOT_FOUND); 703 } 704 705 #ifdef DEBUG 706 for (i = 0; i < ibdp->ibcm_arp_ibd_cnt; i++) { 707 char my_buf[INET6_ADDRSTRLEN]; 708 ibcm_arp_ip_t *aip = &ibdp->ibcm_arp_ip[i]; 709 710 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: ibd[%d]: Family %d " 711 "Instance %d PKey 0x%lX \n HCAGUID 0x%llX SGID %llX:%llX", 712 i, aip->ip_inet_family, aip->ip_inst, aip->ip_pkey, 713 aip->ip_hca_guid, aip->ip_port_gid.gid_prefix, 714 aip->ip_port_gid.gid_guid); 715 if (aip->ip_inet_family == AF_INET) { 716 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: IPV4: %s", 717 inet_ntop(AF_INET, &aip->ip_cm_sin.sin_addr, my_buf, 718 sizeof (my_buf))); 719 } else if (aip->ip_inet_family == AF_INET6) { 720 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_ibds: IPV6: %s", 721 inet_ntop(AF_INET6, &aip->ip_cm_sin6.sin6_addr, 722 my_buf, sizeof (my_buf))); 723 } else { 724 IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_ibds: Unknown " 725 "Family %d", aip->ip_inet_family); 726 } 727 } 728 #endif 729 730 return (IBT_SUCCESS); 731 } 732 733 _NOTE(SCHEME_PROTECTS_DATA("Unshared data", ibtl_cm_port_list_t)) 734 735 ibt_status_t 736 ibcm_arp_get_srcip_plist(ibt_ip_path_attr_t *ipattr, ibt_path_flags_t flags, 737 ibtl_cm_port_list_t **port_list_p) 738 { 739 ibt_path_attr_t attr; 740 ibt_status_t ret; 741 ibcm_arp_ibd_insts_t ibds; 742 ibcm_arp_ip_t *ipp; 743 ibtl_cm_port_list_t *plistp; 744 ib_gid_t sgid; 745 sa_family_t family_interested = AF_UNSPEC; 746 747 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist(%p, %llX)", 748 ipattr, flags); 749 750 if (ipattr->ipa_src_ip.family != AF_UNSPEC) 751 family_interested = ipattr->ipa_src_ip.family; 752 else 753 family_interested = ipattr->ipa_dst_ip[0].family; 754 755 sgid.gid_prefix = sgid.gid_guid = 0; 756 bzero(&ibds, sizeof (ibcm_arp_ibd_insts_t)); 757 ibds.ibcm_arp_ibd_alloc = IBCM_ARP_IBD_INSTANCES; 758 ibds.ibcm_arp_ibd_cnt = 0; 759 ibds.ibcm_arp_ip = (ibcm_arp_ip_t *)kmem_zalloc( 760 ibds.ibcm_arp_ibd_alloc * sizeof (ibcm_arp_ip_t), KM_SLEEP); 761 762 ret = ibcm_arp_get_ibds(&ibds, family_interested); 763 if (ret != IBT_SUCCESS) { 764 IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_srcip_plist: " 765 "ibcm_arp_get_ibds failed : 0x%x", ret); 766 goto srcip_plist_end; 767 } 768 769 if (ipattr->ipa_src_ip.family != AF_UNSPEC) { 770 ret = ibcm_arp_ibd_mac2gid(&ibds, &ipattr->ipa_src_ip, &sgid); 771 if (ret != IBT_SUCCESS) { 772 IBTF_DPRINTF_L2(cmlog, "ibcm_arp_get_srcip_plist: " 773 "SGID for the specified SRCIP Not found %X", ret); 774 goto srcip_plist_end; 775 } 776 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist: SGID " 777 "%llX:%llX", sgid.gid_prefix, sgid.gid_guid); 778 } 779 780 bzero(&attr, sizeof (ibt_path_attr_t)); 781 attr.pa_hca_guid = ipattr->ipa_hca_guid; 782 attr.pa_hca_port_num = ipattr->ipa_hca_port_num; 783 attr.pa_sgid = sgid; 784 bcopy(&ipattr->ipa_mtu, &attr.pa_mtu, sizeof (ibt_mtu_req_t)); 785 bcopy(&ipattr->ipa_srate, &attr.pa_srate, sizeof (ibt_srate_req_t)); 786 bcopy(&ipattr->ipa_pkt_lt, &attr.pa_pkt_lt, sizeof (ibt_pkt_lt_req_t)); 787 788 ret = ibtl_cm_get_active_plist(&attr, flags, port_list_p); 789 if (ret == IBT_SUCCESS) { 790 int i; 791 uint8_t cnt; 792 boolean_t no_srcip_configured = B_FALSE; 793 uint8_t no_srcip_cnt = 0; 794 795 plistp = port_list_p[0]; 796 cnt = plistp->p_count; 797 for (i = 0; i < cnt; i++, plistp++) { 798 ipp = ibcm_arp_ibd_gid2mac(&plistp->p_sgid, 0, &ibds); 799 if ((ipp == NULL) || 800 (ipp->ip_inet_family == AF_UNSPEC)) { 801 plistp->p_src_ip.family = AF_UNSPEC; 802 no_srcip_configured = B_TRUE; 803 no_srcip_cnt++; 804 IBTF_DPRINTF_L3(cmlog, 805 "ibcm_arp_get_srcip_plist: SrcIP NOT " 806 "Configured for GID %llX:%llX", 807 plistp->p_sgid.gid_prefix, 808 plistp->p_sgid.gid_guid); 809 } else { 810 IBTF_DPRINTF_L4(cmlog, 811 "ibcm_arp_get_srcip_plist: GID %llX:%llX", 812 plistp->p_sgid.gid_prefix, 813 plistp->p_sgid.gid_guid); 814 if (ipp->ip_inet_family == AF_INET) { 815 plistp->p_src_ip.family = AF_INET; 816 bcopy(&ipp->ip_cm_sin.sin_addr, 817 &plistp->p_src_ip.un.ip4addr, 818 sizeof (in_addr_t)); 819 820 } else if (ipp->ip_inet_family == AF_INET6) { 821 plistp->p_src_ip.family = AF_INET6; 822 bcopy(&ipp->ip_cm_sin6.sin6_addr, 823 &plistp->p_src_ip.un.ip6addr, 824 sizeof (in6_addr_t)); 825 } 826 IBCM_PRINT_IP("ibcm_arp_get_srcip_plist: " 827 "IP Addr is:", &plistp->p_src_ip); 828 } 829 } 830 if (no_srcip_configured) { 831 ibtl_cm_port_list_t *n_plistp, *tmp_n_plistp; 832 uint8_t new_cnt; 833 834 new_cnt = cnt - no_srcip_cnt; 835 836 /* 837 * Looks like some of the SRC GID we found have no 838 * IP ADDR configured, so remove these entries from 839 * our list. 840 */ 841 plistp = port_list_p[0]; 842 IBTF_DPRINTF_L4(cmlog, "ibcm_arp_get_srcip_plist: " 843 "Only %d SGID (%d/%d) have SrcIP Configured", 844 new_cnt, no_srcip_cnt, cnt); 845 if (new_cnt) { 846 /* Allocate Memory to hold Src Point info. */ 847 n_plistp = kmem_zalloc(new_cnt * 848 sizeof (ibtl_cm_port_list_t), KM_SLEEP); 849 850 tmp_n_plistp = n_plistp; 851 for (i = 0; i < cnt; i++, plistp++) { 852 if (plistp->p_src_ip.family == 853 AF_UNSPEC) 854 continue; 855 856 bcopy(plistp, n_plistp, 857 sizeof (ibtl_cm_port_list_t)); 858 n_plistp->p_count = new_cnt; 859 n_plistp++; 860 } 861 plistp = port_list_p[0]; 862 *port_list_p = tmp_n_plistp; 863 } else { 864 /* 865 * All entries we have, do not have IP-Addr 866 * configured so return empty hand. 867 */ 868 IBTF_DPRINTF_L2(cmlog, 869 "ibcm_arp_get_srcip_plist: None of SGID " 870 "found have SrcIP Configured"); 871 *port_list_p = NULL; 872 ret = IBT_SRC_IP_NOT_FOUND; 873 } 874 IBTF_DPRINTF_L4(cmlog, "FREE OLD list %p, NEW list is " 875 "%p - %p", plistp, port_list_p, *port_list_p); 876 kmem_free(plistp, cnt * sizeof (ibtl_cm_port_list_t)); 877 } 878 } 879 880 srcip_plist_end: 881 if (ibds.ibcm_arp_ip) 882 kmem_free(ibds.ibcm_arp_ip, ibds.ibcm_arp_ibd_alloc * 883 sizeof (ibcm_arp_ip_t)); 884 885 return (ret); 886 } 887 /* Routines for warlock */ 888 889 /* ARGSUSED */ 890 static int 891 ibcm_arp_dummy_ibaddr_hdl(void *arg, int status) 892 { 893 ibcm_arp_prwqn_t dummy_wqn1; 894 ibcm_arp_prwqn_t dummy_wqn2; 895 896 dummy_wqn1.func = ibcm_arp_get_ibaddr_cb; 897 dummy_wqn2.func = ibcm_arp_dummy_ibaddr_hdl; 898 899 IBTF_DPRINTF_L5(cmlog, "ibcm_arp_dummy_ibaddr_hdl: " 900 "dummy_wqn1.func %p %p", dummy_wqn1.func, dummy_wqn2.func); 901 902 return (0); 903 } 904