Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Feb 2025 00:20:31 GMT
From:      Ravi Pokala <rpokala@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 8d079c6a9a5d - main - if_infininband: Support BPF write for broadcast frames
Message-ID:  <202502240020.51O0KVO1074749@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by rpokala:

URL: https://cgit.FreeBSD.org/src/commit/?id=8d079c6a9a5dfdc75adaf9bc31f2ee8111b849a1

commit 8d079c6a9a5dfdc75adaf9bc31f2ee8111b849a1
Author:     Nicholas Dance <ndance@vdura.com>
AuthorDate: 2025-02-05 23:33:20 +0000
Commit:     Ravi Pokala <rpokala@FreeBSD.org>
CommitDate: 2025-02-24 00:13:09 +0000

    if_infininband: Support BPF write for broadcast frames
    
    To support DHCP for IPoIB links, DHCP clients and servers require the
    ability to transmit link-layer broadcasts on the IB interfaces. BPF
    provides the mechanism for doing this.
    
    This change updates the if_infiniband driver to be capable of accepting
    link-layer broadcast requests via BPF using Ethernet formatted frames
    (the driver currently registers with BPF as DLT_EN10MB). Only Broadcast
    frames can reliably be interpreted using the Ethernet header format so
    detect unicast and multicast frames are rejected if passed in using the
    Ethernet format. This doesn't impact the ability to support native
    unicast, broadcast or multicast frames if native infiniband header
    support is added to BPF at a later date.
    
    Further the above, this commit also addresses an issue in the existing
    code that can result in separation of part of the packet header from the
    rest of the payload if a BPF write was attempted. This was caused by
    mbuf preallocation of the infiniband header length regardless of length
    of the prepend data.
    
    Reviewed by:    rpokala; Greg Foster <gfoster@vdura.com>
    Tested by:      Greg Foster <gfoster@vdura.com>
    MFC after:      1 week
    Sponsored by:   Vdura
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/1591
---
 sys/net/if_infiniband.c | 57 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 52 insertions(+), 5 deletions(-)

diff --git a/sys/net/if_infiniband.c b/sys/net/if_infiniband.c
index 7f0bb02f1687..94492421d962 100644
--- a/sys/net/if_infiniband.c
+++ b/sys/net/if_infiniband.c
@@ -149,6 +149,43 @@ infiniband_bpf_mtap(struct ifnet *ifp, struct mbuf *mb)
 	mb->m_pkthdr.len += sizeof(*ibh);
 }
 
+/*
+ * For clients using BPF to send broadcasts.
+ *
+ * This driver binds to BPF as an EN10MB (Ethernet) device type. As such, it is
+ * expected BPF and BPF users will send frames with Ethernet headers, which
+ * we'll do our best to handle. We can't resolve non-native unicast or multicast
+ * link-layer addresses, but we can handle broadcast frames.
+ *
+ * phlen is populated with IB header size if ibh was populated, 0 otherwise.
+ */
+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)
+{
+	struct ether_header *eh = (struct ether_header *)ro->ro_prepend;
+	/* If the prepend data & address length don't have the signature of a frame
+	 * forwarded by BPF, allow frame to passthrough. */
+	if (((ro->ro_flags & RT_HAS_HEADER) == 0) ||
+	    (ro->ro_plen != ETHER_HDR_LEN)) {
+		*phlen = 0;
+		return (0);
+	}
+
+	/* Looks like this frame is from BPF. Handle broadcasts, reject otherwise */
+	if (!ETHER_IS_BROADCAST(eh->ether_dhost))
+		return (EOPNOTSUPP);
+
+	memcpy(ibh->ib_hwaddr, ifp->if_broadcastaddr, sizeof(ibh->ib_hwaddr));
+	ibh->ib_protocol = eh->ether_type;
+	mb->m_flags &= ~M_MCAST;
+	mb->m_flags |= M_BCAST;
+
+	*phlen = INFINIBAND_HDR_LEN;
+	return (0);
+}
+
 static void
 update_mbuf_csumflags(struct mbuf *src, struct mbuf *dst)
 {
@@ -306,7 +343,7 @@ infiniband_output(struct ifnet *ifp, struct mbuf *m,
 	struct llentry *lle = NULL;
 	struct infiniband_header *ih;
 	int error = 0;
-	int hlen;	/* link layer header length */
+	int hlen  = 0;	/* link layer header length */
 	uint32_t pflags;
 	bool addref;
 
@@ -316,10 +353,20 @@ infiniband_output(struct ifnet *ifp, struct mbuf *m,
 	phdr = NULL;
 	pflags = 0;
 	if (ro != NULL) {
-		/* XXX BPF uses ro_prepend */
+		/* XXX BPF and ARP use ro_prepend */
 		if (ro->ro_prepend != NULL) {
-			phdr = ro->ro_prepend;
-			hlen = ro->ro_plen;
+			ih = (struct infiniband_header *)linkhdr;
+			/* Assess whether frame is from BPF and handle */
+			error = infiniband_resolve_bpf(ifp, dst, m, ro, ih, &hlen);
+			if (error != 0)
+				goto bad;
+
+			if (hlen != 0) {
+				phdr = linkhdr;
+			} else {
+				phdr = ro->ro_prepend;
+				hlen = ro->ro_plen;
+			}
 		} else if (!(m->m_flags & (M_BCAST | M_MCAST))) {
 			if ((ro->ro_flags & RT_LLE_CACHE) != 0) {
 				lle = ro->ro_lle;
@@ -386,7 +433,7 @@ infiniband_output(struct ifnet *ifp, struct mbuf *m,
 	 * Add local infiniband header. If no space in first mbuf,
 	 * allocate another.
 	 */
-	M_PREPEND(m, INFINIBAND_HDR_LEN, M_NOWAIT);
+	M_PREPEND(m, hlen, M_NOWAIT);
 	if (m == NULL) {
 		error = ENOBUFS;
 		goto bad;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502240020.51O0KVO1074749>