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