OpenThread Border Router: Fixing Headaches with FW and Routing - #4803
OpenThread Border Router: Fixing Headaches with FW and Routing#4803tannerdsilva wants to merge 19 commits into
Conversation
… leadership weight recognition across the mesh
- COPY 0003-disable-fc00-route.patch and 0004-routing-manager-corrections.patch into the build context (they were applied but never copied: latent build break). - Sync openthread-core-ha-config-posix.h with ts-otbr: enable DISABLE_BROAD_ULA_ROUTE, MULTI_AIL_DETECTION, TRACK_PEER_BR_INFO, USE_HEAP. Routing patches remain byte-identical to ts-otbr (0005==0003, 0006==0004).
…arding) Replace blanket multicast/broadcast drop in both forward chains with scope-gated forwarding per Thread 1.3+ spec: only admin-local scope (ff04::/16) and above cross the BR boundary; mesh-local (ff02/ff03) and broadcast never leak. Add mcast-fwd-scope set. Align MLE/TMF control-plane allow, SRP/ND handling, and forward-chain priority (mangle->filter). Byte-identical to ts-otbr working tree.
…c, wpan-sysctl) Bring the runtime hardening services into the fork, byte-identical to ts-otbr: otbr-route-guard (deletes RA-learned OMR routes), otbr-ipset-sync (continuous ipset->nft set sync), otbr-wpan-sysctl (IPv6 hardening on wpan0). Wire otbr-ipset-sync and otbr-wpan-sysctl into user/contents.d to match ts-otbr.
Enable the RA-route defense service so it actually starts at boot, keeping the s6 service wiring in sync with ts-otbr.
Remove upgrade_threshold and downgrade_threshold from the add-on config schema, defaults, and frontend translations. These expose Thread router upgrade/downgrade targets that are not needed for this submission.
Remove upgrade_threshold and downgrade_threshold from the DOCS.md configuration table and the CHANGELOG docs line, matching the earlier removal of the options from the config UI.
… script The upgrade_threshold and downgrade_threshold options were removed from the config schema and UI, so the bashio blocks that applied them are unreachable. Delete the dead ot-ctl routerupgradethreshold / routerdowngradethreshold handling.
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
|
@tannerdsilva For the fc00::/7 route issue, did you try simply disabling OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE ? ... see also openthread/openthread#13562 |
|
@tannerdsilva and for the firewall topic maybe openthread/ot-br-posix#3325 is the best solution |
|
There's a lot in this. As I'm looking over the diff, I'm seeing things like the "suggested ULA prefix" upstream patch. Things like this are where I started (in speculation), not where I ended (in applied success). Should be removed. I'll shake that out tonight, while also investigating the above concerns. In my opinion, most painful part of this was the border router mDNS leak into thread interface. I have found this is super problematic because it causes "inverted L2 uplinks" and entropy on Thread in general. Unfortunately, it's entropy that can't be power cycled away at all - only time heals. My environment also required an elevated leader weight to resolve a complete offline deadlock after the mDNS loop was capped. My fork started by addressing the fc00::/7 route issue because I knew I had undefined Thread issues, and this seemed like a valid angle to investigate. I then went "scorched earth" on all traffic after seeing no improvement in the routing patches alone. The fc00::/7 patches stayed in because it does seem like an incremental and valid technical improvement to an issue that I didn't discover (therefore couldn't feel entitled to omit it on my own). |
|
IMO: the consistent OMR prefix is important here. I can't say why, other than this:
I think the easiest way to bring existing installations forward on this is to hash a private-range IPv6 OMR prefix from some public data field of the thread credentials (maybe hashing the network name). I will update this PR with this logic because I believe this is a "no downside, only upside" improvement for all network configurations of all sizes. @Apollon77 as described, this static omr prefix with multiple BR is causing my visualization to break as we discussed in DM. |
…to one - Bump build pins to ot-br-posix main tip 4e5cfca4 (includes home-assistant#3325 in-process opt-in nftables backend as the new base) - Drop patches now upstream: 0001 (SO_REUSEADDR), 0002 (NAT64 IPv4 options/security hardening) - Drop speculative ULA-prefix patches (0003/0004) and the broad-ULA-route patch (0005) plus orphaned duplicates - Keep 0006 routing-manager corrections, re-based for the new upstream NetworkDataContainsUlaRoute() logic (kUlaPrefix /7->/64, publish real OMR prefix, never publish ::/0) - Replace 0005 with OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE=0 in the project config header (the upstream #13562 mechanism) - Build validated on clean Ubuntu 24.04 host (amd64, beta+stable, 0 errors)
Build both beta and stable with -DOTBR_NFTABLES=ON: the upstream home-assistant#3325 in-process backend (libnftnl/libmnl) owns the ingress filter and NAT44 and forces OT_FIREWALL off, so there is no legacy ipset producer. Add libnftnl-dev and libmnl-dev to both builder stages. NOTE: runtime wiring in otbr-agent/run is a follow-up commit. Deploying this commit alone would leave the add-on shell firewall without its ipset source.
With -DOTBR_NFTABLES=ON the agent owns unicast ingress into the Thread
interface and NAT44 in-process (OT_FIREWALL is compiled out, so the
classic ipsets are never populated). Adapt otbr-agent/run:
- Detect the backend via the build marker under the OTBR install prefix
(/opt/otbr-{stable,beta}/share/otbr/nftables-backend), env override wins
- Skip legacy ipset creation and ipset->nft sync in backend mode
- Add-on 'ip6 otbr' forward chains end in 'return', so unicast ingress
falls through to the agent's inet otbr forward_ingress (the add-on chain
evaluates first at the same hook/priority; a terminal accept/drop would
terminate the hook and bypass the backend)
- Keep host input/output protection, scope-gated multicast / mDNS
containment, TREL isolation and DOCKER-USER hole; replace the now-empty
ingress allow/deny set matches with rate-limited generic accepts
- Skip the add-on NAT64 table in backend mode (agent owns NAT44 masquerade)
- firewall toggle now slices the add-on layer only
- otbr-ipset-sync exits early in backend mode (nothing to sync)
Image-verified: marker=1 under the prefix, detection=1, backend symbol
present, scripts parse.
When custom_omr_prefix is not set, hash the Thread network name into a ULA /64 (fd00::/8) and apply it via br omrconfig custom. Every border router on the same mesh sees the same network name and therefore derives the same OMR prefix, so multi-BR deployments converge on a single stable prefix without per-BR configuration (matching Apple border-router behavior). custom_omr_prefix remains the frontend-input override, and a configurable priority still applies via custom_omr_priority. The derivation is deterministic (verified: same name -> same /64, unique per name, empty name fails cleanly), applies through the existing ot-ctl br omrconfig path, and retries until the agent reports the network name. DOCS.md/CHANGELOG/translations updated accordingly.
- CHANGELOG: replace stale 4.0.0 build bullets that still described the removed ULA-prefix / broad-ULA-route / SO_REUSEADDR / NAT64 patches with the actual rebased state (single 0006 patch, upstream items dropped, external-route install disabled via the config header, home-assistant#3325 backend and deterministic OMR notes) - Add the refreshed companion documentation (otbr-pr-docs) aligned with the final state of the change: PR_BODY, uplink theory, multicast forwarding, thread-research architecture overview, DOCS and CHANGELOG mirrors The docs now describe the home-assistant#3325 in-process backend plus the retained add-on layer, the deterministic network-name-derived OMR prefix, and the commit chain behind the PR.
|
Ok I think that concludes the development work for now. Working to validate these changes in my environment today... |
What this is for
I run this add-on on a live commercial deployment: a single-floor office around 35,000 sq ft with 450+ Thread devices, six border routers, and two switching racks on one shared L2. At that size, whatever breaks breaks loudly, and it keeps breaking until you fix it. Neither problem this PR fixes was something I read about. Both happened to me, at scale, and both are why the changes here exist.
Routing loop
On a multi-BR network sharing one broadcast domain, a border router can install the broad
fc00::/7ULA route. That swallows the whole ULA space. Devices end up stranded on stale prefixes, and the mesh starts routing in circles.mDNS leak loop
Current OTBR releases leak the agent's mDNS advertisements out of both interfaces,
wpan0and the backbone. On a shared fabric with a second border router, that wraps around. An advertisement leaves one BR'swpan0, crosses the mesh, shows up at the next BR, and comes back out its backbone. The network ends up forwarding its own discovery traffic in a loop.What changed
custom_omr_prefixallows all border routers to operate in the same prefix, which removes the trigger for the catch-all route. Patches0003and0004make the ULA prefix reproducible and persisted.0005puts the broadfc00::/7route behind a compile-time flag. Patch0006tightens the Routing Manager to match exact/64s and publish the real OMR prefix instead of::/0.ip6 otbr(seven chains) replaces the minimalip6tablesrules: default-deny in both forwarding directions, host input and output protection, TREL isolation, scope-gated multicast, ipset-to-nftables sync, and Docker'sDOCKER-USERchain. The scope gate is what contains mDNS. Link-local multicast, where mDNS lives (ff02::fb), is dropped at the boundary in both directions, so an advertisement can't reach another border router and loop.otbr-route-guard,otbr-ipset-sync, andotbr-wpan-sysctlcover the edge cases that only show up under load.A note on the
firewallsettingI want to be upfront about the
firewalltoggle in the app's config frontend. I didn't know what to do with it. Even with that enabled setting in place, the old behavior fell short of actually being enough, and it was hard to see what the firewall was even supposed to be blocking or managing. So this PR rebuilds that layer from the ground up rather than trying to patch the toggle. If anyone can point me at how the firewall rules should best be sliced out for the config UI, I'm glad to re-apply it properly on top of this.Tested where it lives
The network that exposed these bugs is the same one validating the fix. Both loops reproduced at that scale, and both are gone there. The image also builds cleanly from a fresh host. Validating against 450+ nodes across six border routers is a proof most OTBR deployments never get to run.