xref: /freebsd/sys/net/if_infiniband.c (revision 8d079c6a9a5dfdc75adaf9bc31f2ee8111b849a1)
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
infiniband_ipv4_multicast_map(uint32_t addr,const uint8_t * broadcast,uint8_t * buf)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
infiniband_ipv6_multicast_map(const struct in6_addr * addr,const uint8_t * broadcast,uint8_t * buf)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
infiniband_bpf_mtap(struct ifnet * ifp,struct mbuf * mb)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
infiniband_resolve_bpf(struct ifnet * ifp,const struct sockaddr * dst,struct mbuf * mb,const struct route * ro,struct infiniband_header * ibh,int * phlen)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
update_mbuf_csumflags(struct mbuf * src,struct mbuf * dst)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
infiniband_requestencap(struct ifnet * ifp,struct if_encap_req * req)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
infiniband_resolve_addr(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,struct route * ro,uint8_t * phdr,uint32_t * pflags,struct llentry ** plle)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
infiniband_output(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,struct route * ro)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
infiniband_input(struct ifnet * ifp,struct mbuf * m)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
infiniband_resolvemulti(struct ifnet * ifp,struct sockaddr ** llsa,struct sockaddr * sa)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
infiniband_ifattach(struct ifnet * ifp,const uint8_t * lla,const uint8_t * llb)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
infiniband_ifdetach(struct ifnet * ifp)707 infiniband_ifdetach(struct ifnet *ifp)
708 {
709 	bpfdetach(ifp);
710 	if_detach(ifp);
711 }
712 
713 static int
infiniband_modevent(module_t mod,int type,void * data)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