Repository navigation
feat: per-session BFD timers - #28
Merged
Merged
Conversation
A peer with BFD on rendered a bare `bfd;` and one empty `protocol bfd`,
so every session ran BIRD's 100 ms x 5 default: dead after 0.5 s of
silence. That suits a direct link, but iBGP carried over GRE across the
internet flapped several times a day on sub-second loss. The raw-config
escape hatch could not help: BIRD hands each BFD request to the first
BFD protocol that accepts it, and the generated bfd1 accepts everything.
Peers and templates gain an interval (ms) and a multiplier, rendered on
the session alone as `bfd { interval N ms; multiplier M; };` (per-peer
BFD options, BIRD 2.0.8+), so a tunnel can run 300 ms x 10 while a
direct peer beside it keeps the fast default. Both are template-governed
shape fields, validated (10-10000 ms, 1-255; 0 keeps BIRD's default) and
cleared when BFD is off. With both at 0 the session renders a bare
`bfd;`, byte-identical to before. Schema version 39 adds two defaulted
columns each to peers and peer_templates.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- schema.go: peer_templates declares bfd_interval/bfd_multiplier, as its "columns mirror peers" contract requires; v39 still adds them to existing databases. - The interval hint, comment and validation message said 0 means "100 ms". BIRD's defaults are send every 100 ms, accept down to 10 ms, and `interval` sets both, so say that. - Settings > Raw configuration still offered BFD tuning, with a `protocol bfd` placeholder that can never see a BGP session because the generated bfd1 takes every request. Point at the peer form instead. - USAGE: timers need BIRD 2.0.8+, like RFC 9234 roles; the raw-config note no longer reads as if birdy does not validate the timers; note that BIRD shares one BFD session per neighbor address. - Tests: the template block carries the timers and a linked peer does not repeat them (a unit test, not only integration), and a v38 database with BFD peers and templates migrates to zero timers and can then store them (checked failing with the v39 step disabled). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
floreabogdan
force-pushed
the
feat/bfd-timers
branch
from
September 30, 2026 14:23
a830f86 to
e0014d9
Compare
Owner
Author
|
Review follow-up (pushed; rebased onto
Not changed, by design: the timers stay template-governed with no per-peer override (as Re-verified locally on |
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.
Why
A peer with BFD on renders a bare
bfd;, and birdy emits a single emptyprotocol bfd bfd1 {}. Every session therefore runs BIRD's default of 100 ms × 5 and is declared dead after 0.5 s of silence.That suits a direct link but not iBGP carried over GRE across the internet. On rt1/rt2 (AS210622), the tunnel sessions to each other and to pdxnet flapped several times a day. The path to pdxnet showed about 0.4–0.5 % loss, in bursts of up to 300 ms, with 20-minute 10 pps probes. BFD timed out, BGP sent a Cease, and routes were withdrawn for about a minute each time.
The raw-config escape hatch can't fix this. BIRD hands each BFD request to the first BFD protocol that accepts it (
bfd_submit_request()inproto/bfd/bfd.c), and the generatedbfd1accepts everything, so a second protocol in raw config never gets the sessions.What
Peers and templates gain BFD interval (ms) and BFD multiplier. They're rendered on the session alone as
using per-peer BFD session options (BIRD 2.0.8+). A tunnel can run 300 ms × 10 while a direct peer beside it keeps the fast default.
With both left at
0, the session still renders a barebfd;, byte-identical to before. Existing configs don't change on upgrade.Both are template-governed shape fields:
ApplyTo/TemplateFromPeer,updatePeerShape, template CRUD, the template form JSON (bfdInterval/bfdMultiplier), andTestEveryPeerFieldIsClassified. A template save rewrites the timers on every linked peer, and a template'stemplate bgpblock carries them.Validation: interval 10–10000 ms, multiplier 1–255,
0= BIRD's default. Both are cleared when BFD is off, followingvalidateShape's "normalise rather than reject".UI: two fields under the session checkboxes (governed, and locked when inherited), and the templates list chip shows e.g.
BFD 300 ms ×10.Schema version 39: two defaulted columns each on
peersandpeer_templates.Docs: USAGE (option table, template-owned fields, and the raw-config section, which pointed at "BFD tuning") plus CHANGELOG.
Tests (written first, each watched failing)
render:TestBFDTimersRendercovers the timer block, a single timer, and the barebfd;fallback.store: round-trip, validation and normalisation, a template → link → template-save rewrite, plus the new fields inTestEveryPeerFieldIsClassified.web: form → store → edit form; an out-of-range value re-renders with its error; template JSON; templates chip and preview.integration:TestIntegrationBFDTimersParseInBirdrenders a template with timers, a peer linked to it and a standalone peer with its own timers, then runsbird -p. A mutation check confirmed it fails on bad syntax (syntax error, unexpected '{').Verification
GitHub Actions currently won't start jobs ("account is locked due to a billing issue"), so this was verified locally with the same steps as
ci.yml, on go1.26.8 withGOTOOLCHAIN=local: gofmt clean,go vet(including-tags integration) ok, golangci-lint v2.1.6 0 issues,go test -race ./...ok, govulncheck with no reachable vulnerabilities,CGO_ENABLED=0build ok, and the integration tests against BIRD 2.14 (Ubuntu 24.04'sbird2, the same package CI installs) pass. Thebfd { … }syntax also parses on BIRD 2.17.1 (checked withbird -pon rt2).I didn't click through the UI in a browser. The two inputs reuse the existing
field-row/fieldmarkup and the generic governed-field fill inpeer-form.js.🤖 Generated with Claude Code