Skip to content

fix(render): stop logging every route the export catch-all drops - #29

Merged
floreabogdan merged 2 commits into
mainfrom
fix/quiet-export-reject
Sep 30, 2026
Merged

floreabogdan merged 2 commits into
mainfrom
fix/quiet-export-reject

Conversation

@floreabogdan

Copy link
Copy Markdown
Owner

Every generated export filter ends in reject "not permitted by any export policy";, and BIRD logs a reject's message once per route. On a full-table router, that catch-all drops nearly the whole table on each export to an upstream or iBGP peer. It fires on every session (re)establishment and on routine table churn.

On rt1.kicked.ro (full tables from Digi, four iBGP sessions over GRE), the journal held 9,536,490 of these lines covering about three days. journald's rate limiter was suppressing up to ~1.5 M bird.service messages per 30 s window. It dropped the BGP and BFD events along with them, which is exactly what you need when chasing flapping sessions.

Change: the catch-all becomes a bare reject;. The targeted rejects inside the policy functions ("bogon prefix", "RPKI invalid", …) keep their reasons: they fire rarely and say something useful. Nothing reads the message back. The peer page's Rejected on export tab uses show route noexport, not the log.

Test: TestExportChainEndsInReject now asserts that the filter ends in a bare reject; and carries no reject message. It was watched failing against the old rendering first.

Verification: GitHub Actions is currently refusing to start jobs (account billing lock), so this was verified locally with the ci.yml steps, on go1.26.8 with GOTOOLCHAIN=local: gofmt, vet, golangci-lint (0 issues), go test -race ./..., govulncheck (none reachable), build, and the BIRD 2.14 integration test all pass.

If this merges after #21, the CHANGELOG hunk (the [Unreleased] → ### Fixed section) will need a trivial rebase, since #21 adds its own sections there.

🤖 Generated with Claude Code

floreabogdan and others added 2 commits September 30, 2026 17:13
Every generated export filter ended in
`reject "not permitted by any export policy"`, and BIRD logs a reject's
message once per route. On a full-table router that line drops nearly the
whole table on each export to an upstream or iBGP peer, so each session
(re)establishment and routine churn floods syslog. One production router
logged 9.5 million such lines in three days, and journald's rate limiter
then dropped the BGP/BFD session events alongside them.

The catch-all is now a bare `reject;`. The targeted rejects inside policy
functions keep their reasons; they fire rarely and say something useful.
`show route noexport`, behind the peer page's "Rejected on export" tab,
still answers which routes were withheld.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the export fix found the same flood on the import side: an
allow-list (`not in SET`), the default-only rule, an origin AS set, the
origin-only check, and the fail-closed rejects for a disabled or
other-family allow-list all rejected everything not explicitly allowed
with a message, and BIRD logs that message once per route. USAGE even
recommends an allow-list import on iBGP, where the far end sends a full
table.

These catch-alls are now bare `reject;` with the reason as a config
comment, as is the export catch-all. Vetoes (bogon, RPKI invalid,
AS-path, prefix length, first AS) keep their messages: they name one
thing wrong with a route. TestOnlyVetoRejectsCarryAMessage renders every
catch-all and fails on any messaged reject not on the veto list, so a
new one has to be added on purpose.

The code comment and CHANGELOG no longer claim `show route noexport`
says why a route was withheld (it lists which), and the CHANGELOG notes
the change lands on the next apply.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@floreabogdan
floreabogdan force-pushed the fix/quiet-export-reject branch from 7d53f70 to 9f7bd00 Compare September 30, 2026 14:19
@floreabogdan

Copy link
Copy Markdown
Owner Author

Review follow-up (pushed; rebased onto main after #21/#25/#26 landed, CHANGELOG conflict resolved):

  • The same per-route flood existed on the import side. The allow-list catch-all (not in SET), the default-only rule, the origin AS set, the origin-only check, and the fail-closed rejects for a disabled or other-family allow-list are now bare reject; with the reason as a config comment. Vetoes (bogon, RPKI invalid, AS-path, prefix length, first AS) keep their messages.
  • TestOnlyVetoRejectsCarryAMessage renders every catch-all and fails on any messaged reject not on the veto list, so this is guarded as a property rather than one line.
  • The comment and CHANGELOG no longer claim show route noexport says why a route was withheld (it lists which), and the CHANGELOG notes the change lands on the next apply.

Re-verified locally (Actions is still billing-locked): gofmt, vet, golangci-lint, go test -race ./..., govulncheck, build, BIRD 2.14 integration, all green.

@floreabogdan
floreabogdan merged commit 287445b into main Sep 30, 2026
0 of 2 checks passed
@floreabogdan
floreabogdan deleted the fix/quiet-export-reject branch September 30, 2026 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant