This is a size-compatible resubmission of the same report sent on9 October and held for exceeding the400KB list limit. The attached tar.xz contains all228 members of the previously verified ZIP, with identical member bytes. Extract it with tar -xJf bird-bfd-spacing-review-20261013.tar.xz and use the standalone program described below. The exact program and observations are unchanged; no additional defect or fresh execution is claimed. Please treat this as the replacement for the oversized held copy. Bug description BIRD 2.19.3 emits consecutive, unchanged, periodic BFD Control packets closer together than the negotiated minimum after jitter. With a 200 ms negotiated interval, sender-side gaps of 95.588 ms and 9.043 ms were captured in separate native runs. A self-contained normal-configuration program reproduced short gaps in both independently started sessions. The reported pairs are Up, have Poll=Final=0, retain the same discriminators and BFD payload, and have no intervening packet from that sender. This report concerns packet spacing, not session establishment or an alleged security impact. Software version Tested BIRD 2.19.3, source commit 5c6376d3075a58d1d378f6d6a7fd50fc0750a72a, binary SHA256 302cdf17722d7601a15aa06d821c8cb92e5b309324a56d19021394e78f2e9793. The binary was built from that checked-out source in openEuler24.03 under WSL2 on Windows. Both native endpoints use the same binary. Tests used one serial systemd unit with CPUQuota=50%, MemoryMax=256M, MemorySwapMax=0 and TasksMax=32. Source-only comparison with master commit 4e414896c39d366e99c7076f3ddc66f3dd7f65e5 shows the same relevant recurrence and BFD timer setup; that master binary was not tested. How to reproduce Requirements: Linux root, Python3, iproute2, util-linux (unshare/nsenter), tcpdump, systemd and a BIRD2.19.3 executable. Save the attached normal_bfd_interval_review.py unchanged, choose a short owned output directory so Unix socket paths fit, and run: sudo systemd-run --unit=bird-bfd-review-1 --collect --wait --pipe \ -p CPUQuota=50% -p MemoryMax=256M -p MemorySwapMax=0 \ -p TasksMax=32 timeout 180 unshare --net --mount --fork \ python3 /absolute/path/to/normal_bfd_interval_review.py \ --bird /absolute/path/to/bird --output /var/tmp/bfd-review \ --mode bfd_rx_change Run a second fresh unit with --mode bfd_tx_change. The program refuses the host network namespace, creates two owned veth-connected role namespaces (192.0.2.1/2, interfaces bc_dut/bc_peer), configures one unauthenticated asynchronous BFD session per role with minTX=minRX=200ms, idleTX=1s and multiplier3, starts passive timestamp observers and capture before BIRD, and waits for both Up. It collects25 steady Up packets, normally changes only the DUT RX or TX interval to400ms and waits for the matching native Poll/Final, collects25 packets in the affected direction, then restarts both roles with200ms and collects25 restoration packets. No fabricated packets, workload, process pause or shared-service changes are made. Inspect standalone-result.json, endpoint-timing-review.json, both passive timestamp logs and stimulus/restore.pcap. A nonzero short_intervals_beyond10ms count identifies strong short-spacing observations; program exit0 means collection completed, not protocol PASS. All processes created by the program are terminated; cleanup.json verifies their exit and only loopback remains in the outer namespace. Incidence varies with host scheduling, so a zero count in one run does not disprove the retained findings. Expected behavior RFC5880 section6.8.7 requires periodic spacing to respect max(localDesiredMinTX,remoteRequiredMinRX) less0-25% per-packet jitter: minimum150ms for200ms, or300ms for400ms. Immediate Final replies and changed-content packets are explicit exceptions and are excluded from the reported pairs. RFC7419 does not replace that safety margin. All8 RFC5880 errata were reviewed: none changes this pacing requirement. Poll/Final transition rules are checked separately under section6.8.3. Actual behavior The exact attached source (SHA256 b798462dc1892a3133c09db6b11af22328feaa8aafd06b3bb52d983068b79810) completed cleanly in two fresh isolated executions. RX-change execution captured271.856ms at400ms and99.353/131.996ms at restored200ms; TX-change execution captured110.162ms at baseline200ms,267.650ms at400ms and32.013ms at restored200ms. Each is below the corresponding jittered minimum. Earlier dual-endpoint runs captured95.588ms and9.043ms at200ms. Both normal parameter changes and matching Poll/Final were observed; short periodic spacing is a separate finding. Complete raw observations and hashes are attached. Additional information Measurements use AF_PACKET software kernel timestamps, with outgoing packet_type4 and matching incoming type0 frames at the opposite endpoint. Frame hashes and nearest timestamps bind the endpoints, and capture corroborates the DUT-side frames. They are not hardware wire timestamps. In the95.588ms example, delivery delays were44.1/47.7us and observer queues127.1/159.0us; realtime-minus-monotonic offset varied2.5us. The9.043ms example had125.9/113.8us delivery and233.4/224.6us observer queues. These variations cannot explain the shortfall. The95.588ms phase had zero additional cgroup throttle events; the9.043ms phase had four. Scheduling pressure can delay a send, but it is not evidence that a subsequent unchanged periodic packet below the minimum is permitted. RFC5880 section7's deployment cautions are acknowledged. No forwarding failure, downstream policer drop or broader-version impact was tested. Code location and suggested fix Fixed-source links: https://gitlab.nic.cz/labs/bird/-/blob/5c6376d3075a58d1d378f6d6a7fd50fc0750a... (bfd_session_update_tx_interval and bfd_tx_timer_hook) and https://gitlab.nic.cz/labs/bird/-/blob/5c6376d3075a58d1d378f6d6a7fd50fc0750a... (timers_fire). Fact: BFD sets recurrent=.75*T and randomize=.15*T (a legal jitter subset), while timers_fire schedules the successor from the previous expiry before calling the hook, unless that successor is already past loop->last_time. The hook then records cached current_time and calls bfd_send_ctl. An exact extracted-function model with mocked clock/heap/send callback demonstrates the consequence: an event serviced100ms late can leave a successor only50ms after its modeled send, despite a150ms recurrence. This demonstrates scheduler arithmetic, not a full BIRD execution. A likely native mechanism is deadline catch-up after late service, or preemption between rescheduling and send; actual native callback deadlines have not been traced, so that causal attribution remains a hypothesis. Suggested BFD-specific change: use a one-shot periodic timer and anchor the next jittered deadline to a fresh monotonic timestamp of actual successful periodic transmission, auditing buffered/failed sends. Preserve immediate Final/changed-content behavior, deferred Up TX increases until Final, immediate negotiated decreases, Demand/zeroRX suppression and idle/state transitions. Avoid changing every recurrent timer client without auditing its contract. Regress normal mult1/3/255 pacing, delayed callbacks, directional changes and recovery. No BIRD patch has been authored, built or validated. Checklist Fixed tested source and binary recorded; exact attached normal program executed twice in fresh isolation; complete textual steps and dependencies provided; actual native configurations, logs, captures, timestamps, sample identities and cleanup retained; RFC, all errata and relevant update applicability checked; sender/receiver and clock/queue observations separated; successful parameter negotiation distinguished from periodic-spacing anomalies; source facts, model result, native root-cause hypothesis and unverified fix design labeled explicitly; no claim about an untested patch or BIRD3 runtime. This report was prepared with AI assistance and reviewed against the cited source and actual execution evidence. On Fri, 09 Oct 2026 06:32:28 -0700, qipeng ding <goodmandqp@gmail.com> wrote:
Bug description BIRD 2.19.3 emits consecutive, unchanged, periodic BFD Control packets closer together than the negotiated minimum after jitter. With a 200 ms negotiated interval, sender-side gaps of 95.588 ms and 9.043 ms were captured in separate native runs. A self-contained normal-configuration program reproduced short gaps in both independently started sessions. The reported pairs are Up, have Poll=Final=0, retain the same discriminators and BFD payload, and have no intervening packet from that sender. This report concerns packet spacing, not session establishment or an alleged security impact.
Software version Tested BIRD 2.19.3, source commit 5c6376d3075a58d1d378f6d6a7fd50fc0750a72a, binary SHA256 302cdf17722d7601a15aa06d821c8cb92e5b309324a56d19021394e78f2e9793. The binary was built from that checked-out source in openEuler24.03 under WSL2 on Windows. Both native endpoints use the same binary. Tests used one serial systemd unit with CPUQuota=50%, MemoryMax=256M, MemorySwapMax=0 and TasksMax=32. Source-only comparison with master commit 4e414896c39d366e99c7076f3ddc66f3dd7f65e5 shows the same relevant recurrence and BFD timer setup; that master binary was not tested.
How to reproduce Requirements: Linux root, Python3, iproute2, util-linux (unshare/nsenter), tcpdump, systemd and a BIRD2.19.3 executable. Save the attached normal_bfd_interval_review.py unchanged, choose a short owned output directory so Unix socket paths fit, and run:
sudo systemd-run --unit=bird-bfd-review-1 --collect --wait --pipe \ -p CPUQuota=50% -p MemoryMax=256M -p MemorySwapMax=0 \ -p TasksMax=32 timeout 180 unshare --net --mount --fork \ python3 /absolute/path/to/normal_bfd_interval_review.py \ --bird /absolute/path/to/bird --output /var/tmp/bfd-review \ --mode bfd_rx_change
Run a second fresh unit with --mode bfd_tx_change. The program refuses the host network namespace, creates two owned veth-connected role namespaces (192.0.2.1/2, interfaces bc_dut/bc_peer), configures one unauthenticated asynchronous BFD session per role with minTX=minRX=200ms, idleTX=1s and multiplier3, starts passive timestamp observers and capture before BIRD, and waits for both Up. It collects25 steady Up packets, normally changes only the DUT RX or TX interval to400ms and waits for the matching native Poll/Final, collects25 packets in the affected direction, then restarts both roles with200ms and collects25 restoration packets. No fabricated packets, workload, process pause or shared-service changes are made. Inspect standalone-result.json, endpoint-timing-review.json, both passive timestamp logs and stimulus/restore.pcap. A nonzero short_intervals_beyond10ms count identifies strong short-spacing observations; program exit0 means collection completed, not protocol PASS. All processes created by the program are terminated; cleanup.json verifies their exit and only loopback remains in the outer namespace. Incidence varies with host scheduling, so a zero count in one run does not disprove the retained findings.
Expected behavior RFC5880 section6.8.7 requires periodic spacing to respect max(localDesiredMinTX,remoteRequiredMinRX) less0-25% per-packet jitter: minimum150ms for200ms, or300ms for400ms. Immediate Final replies and changed-content packets are explicit exceptions and are excluded from the reported pairs. RFC7419 does not replace that safety margin. All8 RFC5880 errata were reviewed: none changes this pacing requirement. Poll/Final transition rules are checked separately under section6.8.3.
Actual behavior The exact attached source (SHA256 b798462dc1892a3133c09db6b11af22328feaa8aafd06b3bb52d983068b79810) completed cleanly in two fresh isolated executions. RX-change execution captured271.856ms at400ms and99.353/131.996ms at restored200ms; TX-change execution captured110.162ms at baseline200ms,267.650ms at400ms and32.013ms at restored200ms. Each is below the corresponding jittered minimum. Earlier dual-endpoint runs captured95.588ms and9.043ms at200ms. Both normal parameter changes and matching Poll/Final were observed; short periodic spacing is a separate finding. Complete raw observations and hashes are attached.
Additional information Measurements use AF_PACKET software kernel timestamps, with outgoing packet_type4 and matching incoming type0 frames at the opposite endpoint. Frame hashes and nearest timestamps bind the endpoints, and capture corroborates the DUT-side frames. They are not hardware wire timestamps. In the95.588ms example, delivery delays were44.1/47.7us and observer queues127.1/159.0us; realtime-minus-monotonic offset varied2.5us. The9.043ms example had125.9/113.8us delivery and233.4/224.6us observer queues. These variations cannot explain the shortfall. The95.588ms phase had zero additional cgroup throttle events; the9.043ms phase had four. Scheduling pressure can delay a send, but it is not evidence that a subsequent unchanged periodic packet below the minimum is permitted. RFC5880 section7's deployment cautions are acknowledged. No forwarding failure, downstream policer drop or broader-version impact was tested.
Code location and suggested fix Fixed-source links: https://gitlab.nic.cz/labs/bird/-/blob/5c6376d3075a58d1d378f6d6a7fd50fc0750a... (bfd_session_update_tx_interval and bfd_tx_timer_hook) and https://gitlab.nic.cz/labs/bird/-/blob/5c6376d3075a58d1d378f6d6a7fd50fc0750a... (timers_fire). Fact: BFD sets recurrent=.75*T and randomize=.15*T (a legal jitter subset), while timers_fire schedules the successor from the previous expiry before calling the hook, unless that successor is already past loop->last_time. The hook then records cached current_time and calls bfd_send_ctl. An exact extracted-function model with mocked clock/heap/send callback demonstrates the consequence: an event serviced100ms late can leave a successor only50ms after its modeled send, despite a150ms recurrence. This demonstrates scheduler arithmetic, not a full BIRD execution. A likely native mechanism is deadline catch-up after late service, or preemption between rescheduling and send; actual native callback deadlines have not been traced, so that causal attribution remains a hypothesis. Suggested BFD-specific change: use a one-shot periodic timer and anchor the next jittered deadline to a fresh monotonic timestamp of actual successful periodic transmission, auditing buffered/failed sends. Preserve immediate Final/changed-content behavior, deferred Up TX increases until Final, immediate negotiated decreases, Demand/zeroRX suppression and idle/state transitions. Avoid changing every recurrent timer client without auditing its contract. Regress normal mult1/3/255 pacing, delayed callbacks, directional changes and recovery. No BIRD patch has been authored, built or validated.
Checklist Fixed tested source and binary recorded; exact attached normal program executed twice in fresh isolation; complete textual steps and dependencies provided; actual native configurations, logs, captures, timestamps, sample identities and cleanup retained; RFC, all errata and relevant update applicability checked; sender/receiver and clock/queue observations separated; successful parameter negotiation distinguished from periodic-spacing anomalies; source facts, model result, native root-cause hypothesis and unverified fix design labeled explicitly; no claim about an untested patch or BIRD3 runtime. This report was prepared with AI assistance and reviewed against the cited source and actual execution evidence.