Skip to content

timex: filter unreasonable offset values from kernel adjtimex() overflow - #3766

Open
dongjiang1989 wants to merge 2 commits into
prometheus:masterfrom
dongjiang1989:fix-time-offset
Open

timex: filter unreasonable offset values from kernel adjtimex() overflow#3766
dongjiang1989 wants to merge 2 commits into
prometheus:masterfrom
dongjiang1989:fix-time-offset

Conversation

@dongjiang1989

@dongjiang1989 dongjiang1989 commented Jul 31, 2026

Copy link
Copy Markdown
Member

Fixes #3764

On KVM/pvclock guests, adjtimex() can transiently return 2^32 ns (4.294967296s) due to a kernel race condition, causing false-positive NodeClockSkewDetected alerts.

Changes:

  1. Add diagnostic counter node_timex_offset_overflow_total

    • Counts readings where |offset| > 4s
    • Does not modify the raw offset metric
  2. Relax alert threshold to ±60s (was unbounded above)

    • Filters the 4.29s overflow artifact
    • Still catches genuinely broken clocks

No filtering at collection time — raw kernel values are preserved.

@maitymondeep

Copy link
Copy Markdown

Can someone please review this PR?

@SuperQ SuperQ left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improvements to the alert mixin would be reasonable, but they should be much more relaxed than 1 second. What if the actual offset is a year out of date? This would create a false negative situation.

Comment thread collector/timex.go
Comment on lines +188 to +196
offsetSec := float64(timex.Offset) / divisor
if offsetSec > 1.0 || offsetSec < -1.0 {
c.logger.Warn("Discarding unreasonable timex offset value",
"offset_seconds", offsetSec, "status", status)
offsetSec = 0
}

ch <- c.syncStatus.mustNewConstMetric(syncStatus)
ch <- c.offset.mustNewConstMetric(float64(timex.Offset) / divisor)
ch <- c.offset.mustNewConstMetric(offsetSec)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, this is not acceptable.

  • This is far too tight a constraint.
  • We avoid filtering values at collection time.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @SuperQ . I Got it.

  1. Removed collector-side filtering — raw adjtimex() values are now preserved as-is. No more masking or replacing offset values.

  2. Added diagnostic counter node_timex_offset_overflow_total — increments when |offset| > 4s, providing visibility into KVM/pvclock overflow events without modifying the primary metric.

  3. Relaxed alert threshold to ±60s — this filters the 4.29s overflow artifact while still catching genuinely broken clocks (minutes/hours off).

On KVM/pvclock guests, a race condition in the kernel NTP PLL can cause
adjtimex() to return 2^32 ns (4.294967296s) as a transient overflow value,
triggering false-positive NodeClockSkewDetected alerts hundreds of times
per day despite NTP being correctly synchronized.

Add a ±1.0s sanity bound in the timex collector: values exceeding this
threshold are discarded (set to 0) with a warning log, as real NTP sync
never produces offsets of this magnitude. Apply the same bound in the
NodeClockSkewDetected alert expression to provide defense-in-depth at
the rule layer.

Fixes prometheus#3764

Signed-off-by: dongjiang <dongjiang1989@126.com>
Address review feedback from @SuperQ:

1. Remove silent offset filtering at collection time
   - node_exporter should faithfully report kernel values
   - Do not mask or replace offset values

2. Add node_timex_offset_overflow_total counter
   - Monotonically counts readings where |offset| > 4s
   - Provides diagnostic signal for KVM/pvclock overflow artifacts
   - Does not modify the raw offset metric

3. Relax NodeClockSkewDetected alert threshold to ±60s
   - Previous ±1.0s was too tight and risked false negatives
   - 60s provides margin above the 4.29s overflow artifact
   - Still catches genuinely broken clocks (minutes/hours off)

Fixes prometheus#3764

Signed-off-by: dongjiang <dongjiang1989@126.com>
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.

NodeClockSkewDetected false-positives on 2^32 ns overflow from kernel adjtimex() (OpenStack/KVM)

3 participants