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>