bgpd: carry reception time at microsecond precision in BMP adj-in - #22990
bgpd: carry reception time at microsecond precision in BMP adj-in#22990tobez wants to merge 2 commits into
Conversation
Every BMP Route Monitoring per-peer header timestamp is reconstituted from a seconds-only monotonic time_t, so monotime_to_realtime() fills the microsecond field with the sub-second offset between CLOCK_REALTIME and CLOCK_MONOTONIC -- a boot-constant value dressed up as precision, identical in every message until the host reboots. For the pre-policy (Adj-RIB-In) feed full precision is free: the reception time lives in struct bgp_adj_in, is written in exactly one place and read only by the BMP code. Store the microseconds in the struct's padding hole (no size growth on LP64), stamp both fields from a single clock read in bgp_adj_in_set(), and pass bmp_monitor() a monotonic struct timeval, with NULL meaning "time unavailable" in place of the (time_t)(-1L) sentinel (which was also run through monotime_to_realtime() only to throw the result away). Post-policy, Loc-RIB and peer-state timestamps intentionally stay second-precision: their sources are shared time_t fields (bpi->uptime, bgp_rib_uptime, peer->uptime) used across bgpd, and truncating to the second keeps correct floor semantics (reported <= true < reported + 1s) that zeroed microseconds would make strictly worse. Signed-off-by: Anton Berezin <tobez@tobez.org>
Drive several re-announcements of a watched prefix, each spaced by the 5s route-map delay timer, and assert that the microsecond components of their pre-policy timestamps actually differ (maximum pairwise circular distance above 100us). With microseconds fabricated from a seconds-only monotonic timestamp every sample sits within a few microseconds of the boot-constant CLOCK_REALTIME-CLOCK_MONOTONIC offset and the check fails; with genuine reception times the components of updates seconds apart are effectively uniform and the false-failure probability is about 1e-8 per run. No sleeps. Signed-off-by: Anton Berezin <tobez@tobez.org>
Greptile SummaryThis PR preserves microsecond precision for pre-policy BMP Route Monitoring timestamps by storing the complete monotonic Adj-RIB-In reception time and passing nullable
Confidence Score: 5/5The PR appears safe to merge, with the intended pre-policy timestamp precision preserved through every changed storage and BMP emission path. Adj-RIB-In timestamps are captured atomically, all consumers initialize the complete timeval, unavailable timestamps retain their previous zero encoding, and no blocking behavioral or contract failure remains. Important Files Changed
Sequence DiagramsequenceDiagram
participant BGP as BGP update processing
participant Adj as Adj-RIB-In
participant BMP as BMP monitor
participant C as BMP collector
BGP->>BGP: "monotime(&now)"
BGP->>Adj: store now.tv_sec and now.tv_usec
Adj->>BMP: pass monotonic timeval
BMP->>BMP: monotime_to_realtime()
BMP->>C: Route Monitoring header with sec/usec
Reviews (1): Last reviewed commit: "tests: check BMP pre-policy timestamps c..." | Re-trigger Greptile |
|
ci:rerun |
2 similar comments
|
ci:rerun |
|
ci:rerun |
ton31337
left a comment
There was a problem hiding this comment.
What if we change time_t to struct timeval adj->uptime at all? This way we could avoid having adj->uptime_usec?
It would be cleaner but we'll pay for that in memory per entry. The 4-byte |
|
TL;DR: IMO, I prefer maintainability here (using struct timeval) versus adding an additional uptime_usec for struct bgp_adj_in. That's eventually 8-bytes more, but still it's under the same 64 bytes "bucket", 56 (by filling padding gap) versus 64 with the timeval struct. And since it's very small in general (we are not going e.g. from 1 to 2 cache lines by adding timeval, I prefer maintainability. (It's just my opinion, might be wrong completely, sorry, and I'd like to ask @donaldsharp and @eqvinox opinions also). |
BMP Route Monitoring per-peer header timestamps are reconstituted from a
seconds-only monotonic time_t, so monotime_to_realtime() fills the
microsecond field with the sub-second offset between CLOCK_REALTIME and
CLOCK_MONOTONIC -- a boot-constant value, identical in every RM message
until the host reboots.
For the pre-policy (Adj-RIB-In) feed full precision is free: the
reception time lives in struct bgp_adj_in, written in one place and read
only by BMP. Store the microseconds in the struct's padding hole (no
size growth on LP64), stamp both fields from one clock read in
bgp_adj_in_set(), and pass bmp_monitor() a monotonic struct timeval,
NULL meaning "time unavailable" in place of the (time_t)(-1L) sentinel.
Post-policy, Loc-RIB and peer-state timestamps intentionally stay
second-precision: their sources are shared time_t fields used across
bgpd.
Includes a topotest asserting that the microsecond components of
pre-policy updates received seconds apart actually differ.