1 /*- 2 * Copyright (c) 2020 Mellanox Technologies. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include "opt_inet.h" 27 #include "opt_inet6.h" 28 #include "opt_kbd.h" 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/devctl.h> 33 #include <sys/eventhandler.h> 34 #include <sys/kernel.h> 35 #include <sys/mbuf.h> 36 #include <sys/module.h> 37 #include <sys/socket.h> 38 #include <sys/sysctl.h> 39 #ifdef KDB 40 #include <sys/kdb.h> 41 #endif 42 43 #include <net/bpf.h> 44 #include <net/ethernet.h> 45 #include <net/infiniband.h> 46 #include <net/if.h> 47 #include <net/if_var.h> 48 #include <net/if_private.h> 49 #include <net/if_dl.h> 50 #include <net/if_media.h> 51 #include <net/if_lagg.h> 52 #include <net/if_llatbl.h> 53 #include <net/if_types.h> 54 #include <net/netisr.h> 55 #include <net/route.h> 56 #include <netinet/if_ether.h> 57 #include <netinet/in.h> 58 #include <netinet/ip6.h> 59 #include <netinet6/in6_var.h> 60 #include <netinet6/nd6.h> 61 62 #include <security/mac/mac_framework.h> 63 64 /* if_lagg(4) support */ 65 struct mbuf *(*lagg_input_infiniband_p)(struct ifnet *, struct mbuf *); 66 67 #ifdef INET 68 static inline void 69 infiniband_ipv4_multicast_map(uint32_t addr, 70 const uint8_t *broadcast, uint8_t *buf) 71 { 72 uint8_t scope; 73 74 addr = ntohl(addr); 75 scope = broadcast[5] & 0xF; 76 77 buf[0] = 0; 78 buf[1] = 0xff; 79 buf[2] = 0xff; 80 buf[3] = 0xff; 81 buf[4] = 0xff; 82 buf[5] = 0x10 | scope; 83 buf[6] = 0x40; 84 buf[7] = 0x1b; 85 buf[8] = broadcast[8]; 86 buf[9] = broadcast[9]; 87 buf[10] = 0; 88 buf[11] = 0; 89 buf[12] = 0; 90 buf[13] = 0; 91 buf[14] = 0; 92 buf[15] = 0; 93 buf[16] = (addr >> 24) & 0xff; 94 buf[17] = (addr >> 16) & 0xff; 95 buf[18] = (addr >> 8) & 0xff; 96 buf[19] = addr & 0xff; 97 } 98 #endif 99 100 #ifdef INET6 101 static inline void 102 infiniband_ipv6_multicast_map(const struct in6_addr *addr, 103 const uint8_t *broadcast, uint8_t *buf) 104 { 105 uint8_t scope; 106 107 scope = broadcast[5] & 0xF; 108 109 buf[0] = 0; 110 buf[1] = 0xff; 111 buf[2] = 0xff; 112 buf[3] = 0xff; 113 buf[4] = 0xff; 114 buf[5] = 0x10 | scope; 115 buf[6] = 0x60; 116 buf[7] = 0x1b; 117 buf[8] = broadcast[8]; 118 buf[9] = broadcast[9]; 119 memcpy(&buf[10], &addr->s6_addr[6], 10); 120 } 121 #endif 122 123 /* 124 * This is for clients that have an infiniband_header in the mbuf. 125 */ 126 void 127 infiniband_bpf_mtap(struct ifnet *ifp, struct mbuf *mb) 128 { 129 struct infiniband_header *ibh; 130 struct ether_header eh; 131 132 if (!bpf_peers_present(ifp->if_bpf)) 133 return; 134 135 M_ASSERTVALID(mb); 136 if (mb->m_len < sizeof(*ibh)) 137 return; 138 139 ibh = mtod(mb, struct infiniband_header *); 140 eh.ether_type = ibh->ib_protocol; 141 memset(eh.ether_shost, 0, ETHER_ADDR_LEN); 142 memcpy(eh.ether_dhost, ibh->ib_hwaddr + 4, ETHER_ADDR_LEN); 143 mb->m_data += sizeof(*ibh); 144 mb->m_len -= sizeof(*ibh); 145 mb->m_pkthdr.len -= sizeof(*ibh); 146 bpf_mtap2(ifp->if_bpf, &eh, sizeof(eh), mb); 147 mb->m_data -= sizeof(*ibh); 148 mb->m_len += sizeof(*ibh); 149 mb->m_pkthdr.len += sizeof(*ibh); 150 } 151 152 /* 153 * For clients using BPF to send broadcasts. 154 * 155 * This driver binds to BPF as an EN10MB (Ethernet) device type. As such, it is 156 * expected BPF and BPF users will send frames with Ethernet headers, which 157 * we'll do our best to handle. We can't resolve non-native unicast or multicast 158 * link-layer addresses, but we can handle broadcast frames. 159 * 160 * phlen is populated with IB header size if ibh was populated, 0 otherwise. 161 */ 162 static int 163 infiniband_resolve_bpf(struct ifnet *ifp, const struct sockaddr *dst, 164 struct mbuf *mb, const struct route *ro, struct infiniband_header *ibh, 165 int *phlen) 166 { 167 struct ether_header *eh = (struct ether_header *)ro->ro_prepend; 168 /* If the prepend data & address length don't have the signature of a frame 169 * forwarded by BPF, allow frame to passthrough. */ 170 if (((ro->ro_flags & RT_HAS_HEADER) == 0) || 171 (ro->ro_plen != ETHER_HDR_LEN)) { 172 *phlen = 0; 173 return (0); 174 } 175 176 /* Looks like this frame is from BPF. Handle broadcasts, reject otherwise */ 177 if (!ETHER_IS_BROADCAST(eh->ether_dhost)) 178 return (EOPNOTSUPP); 179 180 memcpy(ibh->ib_hwaddr, ifp->if_broadcastaddr, sizeof(ibh->ib_hwaddr)); 181 ibh->ib_protocol = eh->ether_type; 182 mb->m_flags &= ~M_MCAST; 183 mb->m_flags |= M_BCAST; 184 185 *phlen = INFINIBAND_HDR_LEN; 186 return (0); 187 } 188 189 static void 190 update_mbuf_csumflags(struct mbuf *src, struct mbuf *dst) 191 { 192 int csum_flags = 0; 193 194 if (src->m_pkthdr.csum_flags & CSUM_IP) 195 csum_flags |= (CSUM_IP_CHECKED|CSUM_IP_VALID); 196 if (src->m_pkthdr.csum_flags & CSUM_DELAY_DATA) 197 csum_flags |= (CSUM_DATA_VALID|CSUM_PSEUDO_HDR); 198 if (src->m_pkthdr.csum_flags & CSUM_SCTP) 199 csum_flags |= CSUM_SCTP_VALID; 200 dst->m_pkthdr.csum_flags |= csum_flags; 201 if (csum_flags & CSUM_DATA_VALID) 202 dst->m_pkthdr.csum_data = 0xffff; 203 } 204 205 /* 206 * Handle link-layer encapsulation requests. 207 */ 208 static int 209 infiniband_requestencap(struct ifnet *ifp, struct if_encap_req *req) 210 { 211 struct infiniband_header *ih; 212 struct arphdr *ah; 213 uint16_t etype; 214 const uint8_t *lladdr; 215 216 if (req->rtype != IFENCAP_LL) 217 return (EOPNOTSUPP); 218 219 if (req->bufsize < INFINIBAND_HDR_LEN) 220 return (ENOMEM); 221 222 ih = (struct infiniband_header *)req->buf; 223 lladdr = req->lladdr; 224 req->lladdr_off = 0; 225 226 switch (req->family) { 227 case AF_INET: 228 etype = htons(ETHERTYPE_IP); 229 break; 230 case AF_INET6: 231 etype = htons(ETHERTYPE_IPV6); 232 break; 233 case AF_ARP: 234 ah = (struct arphdr *)req->hdata; 235 ah->ar_hrd = htons(ARPHRD_INFINIBAND); 236 237 switch (ntohs(ah->ar_op)) { 238 case ARPOP_REVREQUEST: 239 case ARPOP_REVREPLY: 240 etype = htons(ETHERTYPE_REVARP); 241 break; 242 case ARPOP_REQUEST: 243 case ARPOP_REPLY: 244 default: 245 etype = htons(ETHERTYPE_ARP); 246 break; 247 } 248 249 if (req->flags & IFENCAP_FLAG_BROADCAST) 250 lladdr = ifp->if_broadcastaddr; 251 break; 252 default: 253 return (EAFNOSUPPORT); 254 } 255 256 ih->ib_protocol = etype; 257 ih->ib_reserved = 0; 258 memcpy(ih->ib_hwaddr, lladdr, INFINIBAND_ADDR_LEN); 259 req->bufsize = sizeof(struct infiniband_header); 260 261 return (0); 262 } 263 264 static int 265 infiniband_resolve_addr(struct ifnet *ifp, struct mbuf *m, 266 const struct sockaddr *dst, struct route *ro, uint8_t *phdr, 267 uint32_t *pflags, struct llentry **plle) 268 { 269 #if defined(INET) || defined(INET6) 270 struct infiniband_header *ih = (struct infiniband_header *)phdr; 271 #endif 272 uint32_t lleflags = 0; 273 int error = 0; 274 275 if (plle) 276 *plle = NULL; 277 278 switch (dst->sa_family) { 279 #ifdef INET 280 case AF_INET: 281 if ((m->m_flags & (M_BCAST | M_MCAST)) == 0) { 282 error = arpresolve(ifp, 0, m, dst, phdr, &lleflags, plle); 283 } else { 284 if (m->m_flags & M_BCAST) { 285 memcpy(ih->ib_hwaddr, ifp->if_broadcastaddr, 286 INFINIBAND_ADDR_LEN); 287 } else { 288 infiniband_ipv4_multicast_map( 289 ((const struct sockaddr_in *)dst)->sin_addr.s_addr, 290 ifp->if_broadcastaddr, ih->ib_hwaddr); 291 } 292 ih->ib_protocol = htons(ETHERTYPE_IP); 293 ih->ib_reserved = 0; 294 } 295 break; 296 #endif 297 #ifdef INET6 298 case AF_INET6: 299 if ((m->m_flags & M_MCAST) == 0) { 300 int af = RO_GET_FAMILY(ro, dst); 301 error = nd6_resolve(ifp, LLE_SF(af, 0), m, dst, phdr, 302 &lleflags, plle); 303 } else { 304 infiniband_ipv6_multicast_map( 305 &((const struct sockaddr_in6 *)dst)->sin6_addr, 306 ifp->if_broadcastaddr, ih->ib_hwaddr); 307 ih->ib_protocol = htons(ETHERTYPE_IPV6); 308 ih->ib_reserved = 0; 309 } 310 break; 311 #endif 312 default: 313 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 314 if (m != NULL) 315 m_freem(m); 316 return (EAFNOSUPPORT); 317 } 318 319 if (error == EHOSTDOWN) { 320 if (ro != NULL && (ro->ro_flags & RT_HAS_GW) != 0) 321 error = EHOSTUNREACH; 322 } 323 324 if (error != 0) 325 return (error); 326 327 *pflags = RT_MAY_LOOP; 328 if (lleflags & LLE_IFADDR) 329 *pflags |= RT_L2_ME; 330 331 return (0); 332 } 333 334 /* 335 * Infiniband output routine. 336 */ 337 static int 338 infiniband_output(struct ifnet *ifp, struct mbuf *m, 339 const struct sockaddr *dst, struct route *ro) 340 { 341 uint8_t linkhdr[INFINIBAND_HDR_LEN]; 342 uint8_t *phdr; 343 struct llentry *lle = NULL; 344 struct infiniband_header *ih; 345 int error = 0; 346 int hlen = 0; /* link layer header length */ 347 uint32_t pflags; 348 bool addref; 349 350 NET_EPOCH_ASSERT(); 351 352 addref = false; 353 phdr = NULL; 354 pflags = 0; 355 if (ro != NULL) { 356 /* XXX BPF and ARP use ro_prepend */ 357 if (ro->ro_prepend != NULL) { 358 ih = (struct infiniband_header *)linkhdr; 359 /* Assess whether frame is from BPF and handle */ 360 error = infiniband_resolve_bpf(ifp, dst, m, ro, ih, &hlen); 361 if (error != 0) 362 goto bad; 363 364 if (hlen != 0) { 365 phdr = linkhdr; 366 } else { 367 phdr = ro->ro_prepend; 368 hlen = ro->ro_plen; 369 } 370 } else if (!(m->m_flags & (M_BCAST | M_MCAST))) { 371 if ((ro->ro_flags & RT_LLE_CACHE) != 0) { 372 lle = ro->ro_lle; 373 if (lle != NULL && 374 (lle->la_flags & LLE_VALID) == 0) { 375 LLE_FREE(lle); 376 lle = NULL; /* redundant */ 377 ro->ro_lle = NULL; 378 } 379 if (lle == NULL) { 380 /* if we lookup, keep cache */ 381 addref = 1; 382 } else 383 /* 384 * Notify LLE code that 385 * the entry was used 386 * by datapath. 387 */ 388 llentry_provide_feedback(lle); 389 } 390 if (lle != NULL) { 391 phdr = lle->r_linkdata; 392 hlen = lle->r_hdrlen; 393 pflags = lle->r_flags; 394 } 395 } 396 } 397 398 #ifdef MAC 399 error = mac_ifnet_check_transmit(ifp, m); 400 if (error) 401 goto bad; 402 #endif 403 404 M_PROFILE(m); 405 if (ifp->if_flags & IFF_MONITOR) { 406 error = ENETDOWN; 407 goto bad; 408 } 409 if (!((ifp->if_flags & IFF_UP) && 410 (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 411 error = ENETDOWN; 412 goto bad; 413 } 414 415 if (phdr == NULL) { 416 /* No prepend data supplied. Try to calculate ourselves. */ 417 phdr = linkhdr; 418 hlen = INFINIBAND_HDR_LEN; 419 error = infiniband_resolve_addr(ifp, m, dst, ro, phdr, &pflags, 420 addref ? &lle : NULL); 421 if (addref && lle != NULL) 422 ro->ro_lle = lle; 423 if (error != 0) 424 return (error == EWOULDBLOCK ? 0 : error); 425 } 426 427 if ((pflags & RT_L2_ME) != 0) { 428 update_mbuf_csumflags(m, m); 429 return (if_simloop(ifp, m, RO_GET_FAMILY(ro, dst), 0)); 430 } 431 432 /* 433 * Add local infiniband header. If no space in first mbuf, 434 * allocate another. 435 */ 436 M_PREPEND(m, hlen, M_NOWAIT); 437 if (m == NULL) { 438 error = ENOBUFS; 439 goto bad; 440 } 441 if ((pflags & RT_HAS_HEADER) == 0) { 442 ih = mtod(m, struct infiniband_header *); 443 memcpy(ih, phdr, hlen); 444 } 445 446 /* 447 * Queue message on interface, update output statistics if 448 * successful, and start output if interface not yet active. 449 */ 450 return (ifp->if_transmit(ifp, m)); 451 bad: 452 if (m != NULL) 453 m_freem(m); 454 return (error); 455 } 456 457 /* 458 * Process a received Infiniband packet. 459 */ 460 static void 461 infiniband_input(struct ifnet *ifp, struct mbuf *m) 462 { 463 struct infiniband_header *ibh; 464 struct epoch_tracker et; 465 int isr; 466 bool needs_epoch; 467 468 needs_epoch = (ifp->if_flags & IFF_NEEDSEPOCH); 469 #ifdef INVARIANTS 470 /* 471 * This temporary code is here to prevent epoch unaware and unmarked 472 * drivers to panic the system. Once all drivers are taken care of, 473 * the whole INVARIANTS block should go away. 474 */ 475 if (!needs_epoch && !in_epoch(net_epoch_preempt)) { 476 static bool printedonce; 477 478 needs_epoch = true; 479 if (!printedonce) { 480 printedonce = true; 481 if_printf(ifp, "called %s w/o net epoch! " 482 "PLEASE file a bug report.", __func__); 483 #ifdef KDB 484 kdb_backtrace(); 485 #endif 486 } 487 } 488 #endif 489 490 CURVNET_SET_QUIET(ifp->if_vnet); 491 if (__predict_false(needs_epoch)) 492 NET_EPOCH_ENTER(et); 493 494 if ((ifp->if_flags & IFF_UP) == 0) { 495 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 496 m_freem(m); 497 goto done; 498 } 499 500 ibh = mtod(m, struct infiniband_header *); 501 502 /* 503 * Reset layer specific mbuf flags to avoid confusing upper 504 * layers: 505 */ 506 m->m_flags &= ~M_VLANTAG; 507 m_clrprotoflags(m); 508 509 if (INFINIBAND_IS_MULTICAST(ibh->ib_hwaddr)) { 510 if (memcmp(ibh->ib_hwaddr, ifp->if_broadcastaddr, 511 ifp->if_addrlen) == 0) 512 m->m_flags |= M_BCAST; 513 else 514 m->m_flags |= M_MCAST; 515 if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); 516 } 517 518 /* Let BPF have it before we strip the header. */ 519 infiniband_bpf_mtap(ifp, m); 520 521 /* Allow monitor mode to claim this frame, after stats are updated. */ 522 if (ifp->if_flags & IFF_MONITOR) { 523 m_freem(m); 524 goto done; 525 } 526 527 /* Direct packet to correct FIB based on interface config. */ 528 M_SETFIB(m, ifp->if_fib); 529 530 /* Handle input from a lagg<N> port */ 531 if (ifp->if_type == IFT_INFINIBANDLAG) { 532 KASSERT(lagg_input_infiniband_p != NULL, 533 ("%s: if_lagg not loaded!", __func__)); 534 m = (*lagg_input_infiniband_p)(ifp, m); 535 if (__predict_false(m == NULL)) 536 goto done; 537 ifp = m->m_pkthdr.rcvif; 538 } 539 540 /* 541 * Dispatch frame to upper layer. 542 */ 543 switch (ibh->ib_protocol) { 544 #ifdef INET 545 case htons(ETHERTYPE_IP): 546 isr = NETISR_IP; 547 break; 548 549 case htons(ETHERTYPE_ARP): 550 if (ifp->if_flags & IFF_NOARP) { 551 /* Discard packet if ARP is disabled on interface */ 552 m_freem(m); 553 goto done; 554 } 555 isr = NETISR_ARP; 556 break; 557 #endif 558 #ifdef INET6 559 case htons(ETHERTYPE_IPV6): 560 isr = NETISR_IPV6; 561 break; 562 #endif 563 default: 564 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 565 m_freem(m); 566 goto done; 567 } 568 569 /* Strip off the Infiniband header. */ 570 m_adj(m, INFINIBAND_HDR_LEN); 571 572 #ifdef MAC 573 /* 574 * Tag the mbuf with an appropriate MAC label before any other 575 * consumers can get to it. 576 */ 577 mac_ifnet_create_mbuf(ifp, m); 578 #endif 579 /* Allow monitor mode to claim this frame, after stats are updated. */ 580 netisr_dispatch(isr, m); 581 done: 582 if (__predict_false(needs_epoch)) 583 NET_EPOCH_EXIT(et); 584 CURVNET_RESTORE(); 585 } 586 587 static int 588 infiniband_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 589 struct sockaddr *sa) 590 { 591 struct sockaddr_dl *sdl; 592 #ifdef INET 593 struct sockaddr_in *sin; 594 #endif 595 #ifdef INET6 596 struct sockaddr_in6 *sin6; 597 #endif 598 uint8_t *e_addr; 599 600 switch (sa->sa_family) { 601 case AF_LINK: 602 /* 603 * No mapping needed. Just check that it's a valid MC address. 604 */ 605 sdl = (struct sockaddr_dl *)sa; 606 e_addr = LLADDR(sdl); 607 if (!INFINIBAND_IS_MULTICAST(e_addr)) 608 return (EADDRNOTAVAIL); 609 *llsa = NULL; 610 return 0; 611 612 #ifdef INET 613 case AF_INET: 614 sin = (struct sockaddr_in *)sa; 615 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 616 return (EADDRNOTAVAIL); 617 sdl = link_init_sdl(ifp, *llsa, IFT_INFINIBAND); 618 sdl->sdl_alen = INFINIBAND_ADDR_LEN; 619 e_addr = LLADDR(sdl); 620 infiniband_ipv4_multicast_map( 621 sin->sin_addr.s_addr, ifp->if_broadcastaddr, e_addr); 622 *llsa = (struct sockaddr *)sdl; 623 return (0); 624 #endif 625 #ifdef INET6 626 case AF_INET6: 627 sin6 = (struct sockaddr_in6 *)sa; 628 /* 629 * An IP6 address of 0 means listen to all of the 630 * multicast address used for IP6. This has no meaning 631 * in infiniband. 632 */ 633 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) 634 return (EADDRNOTAVAIL); 635 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 636 return (EADDRNOTAVAIL); 637 sdl = link_init_sdl(ifp, *llsa, IFT_INFINIBAND); 638 sdl->sdl_alen = INFINIBAND_ADDR_LEN; 639 e_addr = LLADDR(sdl); 640 infiniband_ipv6_multicast_map( 641 &sin6->sin6_addr, ifp->if_broadcastaddr, e_addr); 642 *llsa = (struct sockaddr *)sdl; 643 return (0); 644 #endif 645 default: 646 return (EAFNOSUPPORT); 647 } 648 } 649 650 void 651 infiniband_ifattach(struct ifnet *ifp, const uint8_t *lla, const uint8_t *llb) 652 { 653 struct sockaddr_dl *sdl; 654 struct ifaddr *ifa; 655 int i; 656 657 ifp->if_addrlen = INFINIBAND_ADDR_LEN; 658 ifp->if_hdrlen = INFINIBAND_HDR_LEN; 659 ifp->if_mtu = INFINIBAND_MTU; 660 if_attach(ifp); 661 ifp->if_output = infiniband_output; 662 ifp->if_input = infiniband_input; 663 ifp->if_resolvemulti = infiniband_resolvemulti; 664 ifp->if_requestencap = infiniband_requestencap; 665 666 if (ifp->if_baudrate == 0) 667 ifp->if_baudrate = IF_Gbps(10); /* default value */ 668 if (llb != NULL) 669 ifp->if_broadcastaddr = llb; 670 671 ifa = ifp->if_addr; 672 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 673 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 674 sdl->sdl_type = IFT_INFINIBAND; 675 sdl->sdl_alen = ifp->if_addrlen; 676 677 if (lla != NULL) { 678 memcpy(LLADDR(sdl), lla, ifp->if_addrlen); 679 680 if (ifp->if_hw_addr != NULL) 681 memcpy(ifp->if_hw_addr, lla, ifp->if_addrlen); 682 } else { 683 lla = LLADDR(sdl); 684 } 685 686 /* Attach ethernet compatible network device */ 687 bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN); 688 689 /* Announce Infiniband MAC address if non-zero. */ 690 for (i = 0; i < ifp->if_addrlen; i++) 691 if (lla[i] != 0) 692 break; 693 if (i != ifp->if_addrlen) 694 if_printf(ifp, "Infiniband address: %20D\n", lla, ":"); 695 696 /* Add necessary bits are setup; announce it now. */ 697 EVENTHANDLER_INVOKE(infiniband_ifattach_event, ifp); 698 699 if (IS_DEFAULT_VNET(curvnet)) 700 devctl_notify("INFINIBAND", ifp->if_xname, "IFATTACH", NULL); 701 } 702 703 /* 704 * Perform common duties while detaching an Infiniband interface 705 */ 706 void 707 infiniband_ifdetach(struct ifnet *ifp) 708 { 709 bpfdetach(ifp); 710 if_detach(ifp); 711 } 712 713 static int 714 infiniband_modevent(module_t mod, int type, void *data) 715 { 716 switch (type) { 717 case MOD_LOAD: 718 case MOD_UNLOAD: 719 return (0); 720 default: 721 return (EOPNOTSUPP); 722 } 723 } 724 725 static moduledata_t infiniband_mod = { 726 .name = "if_infiniband", 727 .evhand = &infiniband_modevent, 728 }; 729 730 DECLARE_MODULE(if_infiniband, infiniband_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 731 MODULE_VERSION(if_infiniband, 1); 732