Add unit tests for packet parsing/serialization, interval arithmetic, the
session state machine, validation discards, poll/final, the detection
watchdog, hook scripts, and socket binding.
Fixes:
- BfdAuth parsing subtracted the header from Auth Len twice; Auth Len
includes the 2-byte header.
- A diagnostic code above 9 panicked the session task; map it to Reserved.
- script_runner panicked on non-UTF-8 script output; decode lossily.
- BfdError::InvalidFieldValue printed field and value swapped.
- BfdInterval now panics on values exceeding u32 microseconds instead of
silently truncating, and gains checked_mul. Detection time computation
saturates rather than panicking on remote-supplied multipliers.
The runtime image contains only the binary and an empty hooks directory, and runs as an unprivileged numeric user. Hook scripts need a shell, so they will not run in this image.
Log the first unmatched packet per source (WARN for an unconfigured source address, INFO for an unknown Your Discriminator) and the repeats at DEBUG until a packet matches again. Removes the duplicate message in rx_packet.
RFC 5880 6.8.7 says a packet SHOULD be sent between periodic transmissions when its contents would change, so peers see state changes without waiting up to a full interval.
Jitter was added to a fixed 0.75x clock, so gaps ranged 0.5x-1.0x with a mean of 0.75x of the negotiated interval, below the required 75-100%. Each delay is now drawn independently from 75-100% of the interval (90-100% when DetectMult is 1). Adds statistical and end-to-end sender tests.
Bind addresses and peers are now optional on the command line and merged with the config file. Per-peer timers and detect multiplier are passed through to the session. Multiple bind addresses are accepted by the model but rejected at startup until supported.
Config is layered: built-in defaults, then the YAML file, then BFD_* environment variables, then CLI flags. Global defaults live under a 'defaults' mapping; per-peer settings are file-only. Includes config.yaml.dist and ScriptHookSink::with_script_dir so the hooks directory is configurable.
Multi-stage build producing a slim image with rust-bfdd as the entrypoint. Dependencies are built against stub sources in their own layer so source-only changes do not rebuild them.
Implement the Poll Sequence (initiate on reaching Up when the configured interval is lower than the slow-start one; respond to Poll with Final; terminate on Final) and apply DesiredMinTxInterval changes per RFC 5880 section 6.8.3, keeping the slow rate until the peer has acknowledged. Never set the Demand bit unless demand mode is active, clear the C bit (this implementation shares fate with the control plane), discard packets whose Length exceeds the received payload, and log effective timer changes.
Select a random unused source port in the RFC 5881 range (retrying on EADDRINUSE) instead of unwrapping a pure-random bind. Propagate bind errors out of session start-up, store the local IP on the session instead of unwrapping local_addr(), and log (rather than panic on) receive errors in the rx loop.
Replace the hard-coded addresses with clap arguments: --bind <IP> and one or more --peer <IP>. Peers must match the address family of the bind address. Also updates Cargo.lock.
Can now establish and hold a session with BIRD, successfully detect Down
state, and call scripts on state change via an event dispatch engine.
Can't maintain a session with VyOS. I think it is calculating the timers
incorrectly, but don't trust my own implementation of course...