fix(util/net): make zenoh build on FreeBSD and support bind-to-device there - #2656
Open
apbodrov wants to merge 1 commit into
Open
fix(util/net): make zenoh build on FreeBSD and support bind-to-device there#2656apbodrov wants to merge 1 commit into
apbodrov wants to merge 1 commit into
Conversation
apbodrov
force-pushed
the
feat/freebsd-bind-to-device
branch
from
June 26, 2026 08:43
0db485e to
06b090d
Compare
diogomatsubara
suggested changes
Jul 23, 2026
diogomatsubara
left a comment
Contributor
There was a problem hiding this comment.
@apbodrov Thanks for your contribution! You'd need to sign the Eclipse contributor agreement so we're able to merge this change.
apbodrov
force-pushed
the
feat/freebsd-bind-to-device
branch
from
July 26, 2026 21:02
06b090d to
5a86785
Compare
zenoh does not currently build on FreeBSD: set_bind_to_device_tcp_socket and set_bind_to_device_udp_socket are defined only for linux/android and for macos/ios/windows, so zenoh-link-commons fails to compile there. FreeBSD cannot implement those functions as written. It has no SO_BINDTODEVICE / IP_BOUND_IF equivalent — there is no such sockopt in netinet/in.h, netinet6/in6.h or sys/socket.h — so the interface cannot be selected once the socket exists. Restrict the socket to the interface by binding one of that interface's own addresses instead, resolved before the single bind(2) call each caller already makes. FreeBSD therefore gets an address resolver rather than a warning stub: a function that can only be called too late to have any effect is worse than no function at all. A concrete address is validated against the interface rather than rewritten, so a mismatched configuration is reported instead of binding somewhere the caller never asked for. For an unspecified address a routable address of the matching family is preferred over a link-local, and a link-local carries the interface index as its scope id, without which FreeBSD rejects the bind with EADDRNOTAVAIL. Behaviour on other platforms is unchanged. Note that zenoh-link-udp still does not build on FreeBSD: its pktinfo module uses the Linux-only IP_PKTINFO and in_pktinfo. That is a separate pre-existing gap, previously masked by zenoh-link-commons failing to compile first. Signed-off-by: Andrey Bodrov <ap.bodrov@gmail.com>
apbodrov
force-pushed
the
feat/freebsd-bind-to-device
branch
from
July 26, 2026 21:08
5a86785 to
02900ff
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
zenoh does not build on FreeBSD at all.
set_bind_to_device_tcp_socketandset_bind_to_device_udp_socketare defined only forlinux | androidand formacos | ios | windows, so on FreeBSDzenoh-link-commonsfails to compile withcannot find function ... in module 'zenoh_util::net'— regardless of whetherifaceis ever used.This PR makes FreeBSD compile, and makes the
ifaceoption actually work there.Why FreeBSD can't just be added to the existing
any()listThere is no
SO_BINDTODEVICE/IP_BOUND_IF/IPV6_BOUND_IFon FreeBSD — no such sockopt exists innetinet/in.h,netinet6/in6.horsys/socket.h. Those are Darwin/Solaris options, not FreeBSD ones.So
set_bind_to_device_*cannot be implemented on FreeBSD in any form: by the time either function is called the socket is already bound, and a socket can only be bound once. Addingfreebsdto theany()list would only produce a warning stub, i.e. a function that silently does nothing while the user believesifacetook effect.The one mechanism FreeBSD does offer is binding the socket to one of the interface's own addresses. That must happen before the single
bind(2)call each caller already makes — which is why FreeBSD gets an address resolver used at the call sites, rather than anotherset_bind_to_device_*arm.What this PR does
zenoh-util— addsresolve_bind_addr_for_interface(iface, addr), FreeBSD-only.zenoh-link-commons(tcp.rs,quic/socket.rs) andzenoh-link-udp(unicast.rs) — on FreeBSD, resolve the bind address beforebind(). On every other platform the existingset_bind_to_device_*call is untouched.Resolution semantics:
0.0.0.0/::) selects an address of the same family from the interface, preferring a routable address over a link-local one, skipping loopback.EADDRNOTAVAIL, which makesiface+ IPv6 unusable.One caveat worth stating: the interface list is a process-lifetime snapshot, so an address assigned to the interface after startup is not visible. This is inherent to resolving an address instead of naming a device.
Behaviour on other platforms
Unchanged. Every new code path is behind
#[cfg(target_os = "freebsd")].Testing
cargo check --target x86_64-unknown-freebsd --all-featuresforzenoh-utilandzenoh-link-commons— clean. This is the check that fails onmain.cargo check --all-featureson Linux for those two crates pluszenoh-link-udp— clean, no regression.ifaceset binds that interface's address and is reachable on it;ifaceset binds successfully — it fails withEADDRNOTAVAILwithout the scope-id handling;iface, behaviour is identical to before.There is no automated coverage for this, because there is no FreeBSD runner in CI — the verification above was done by hand. Happy to follow whatever the project prefers here.
Known gap, not addressed here
zenoh-link-udpstill does not compile on FreeBSD, for a reason unrelated to this change:src/pktinfo/pktinfo_unix.rsuses the Linux-onlyIP_PKTINFOandin_pktinfo(FreeBSD hasIP_RECVDSTADDR/IP_RECVIFinstead). This was previously masked, sincezenoh-link-commonsfailed to compile first. I've left it alone to keep this PR to one concern — glad to open a separate issue or PR for it.Related Issues
None. This is a build fix for FreeBSD support.
🏷️ Label-Based Checklist
Based on the labels applied to this PR, please complete these additional requirements:
Labels:
enhancement✨ Enhancement Requirements
Since this PR enhances existing functionality:
Remember: Enhancements should not introduce new APIs or breaking changes.
Instructions:
- [ ]to- [x])This checklist updates automatically when labels change, but preserves your checked boxes.
On the one unchecked box: this PR does add one new public item,
zenoh_util::net::resolve_bind_addr_for_interface, so "No new APIs added" cannot honestly be ticked. It has to bepubbecausezenoh-link-commonsandzenoh-link-udpcall it across crate boundaries, and it is#[cfg(target_os = "freebsd")], so it does not widen the API surface on any platform that builds today.This is really a build fix rather than an enhancement, so the
enhancementchecklist is a slightly awkward fit. I don't have permission to relabel — if a maintainer retags this asbug, the checklist should regenerate accordingly.