From 0e978f02c090a86bf4bf0c668d8fd01d03d74f80 Mon Sep 17 00:00:00 2001 From: Milan Lenco Date: Thu, 14 Sep 2023 18:58:05 +0200 Subject: [PATCH] Do not suspend DPC testing when clocks are not synchronized If DPC is failing connectivity tests (due to some transient network issue) and device is powered off for long enough that clocks loose time (or there is no battery to keep them running), device will not be able to establish connectivity after power on for a very long time. This is because we demand that failed DPC is tried again only after some time elapses (5 minutes) since the last failed connectivity test. However, when device starts with clocks reset at time "zero" (i.e. start of the epoch), it will take many decades until the current time (as reported by clocks) is past the last failure timestamp. The solution is to detect unsync clocks and allow to test and use DPC immediately. Signed-off-by: Milan Lenco (cherry picked from commit b3bdbc6ebc9151caa4544017c28274b7bb364c13) --- pkg/pillar/types/zedroutertypes.go | 8 ++++ pkg/pillar/types/zedroutertypes_test.go | 51 +++++++++++++++++-------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/pkg/pillar/types/zedroutertypes.go b/pkg/pillar/types/zedroutertypes.go index 78df18375a..a3d6c36a30 100644 --- a/pkg/pillar/types/zedroutertypes.go +++ b/pkg/pillar/types/zedroutertypes.go @@ -861,6 +861,14 @@ func (config DevicePortConfig) IsDPCTestable(minTimeSinceFailure time.Duration) if config.LastSucceeded.After(config.LastFailed) { return true } + if config.LastFailed.After(time.Now()) { + // Clocks are not in sync - most likely they are still around + // the start of the epoch. + // Network is likely needed to synchronize the clocks using NTP, + // and we should attempt to establish network connectivity using + // any DPC available. + return true + } return time.Since(config.LastFailed) >= minTimeSinceFailure } diff --git a/pkg/pillar/types/zedroutertypes_test.go b/pkg/pillar/types/zedroutertypes_test.go index ac7f43f4b4..cf0b70c4d7 100755 --- a/pkg/pillar/types/zedroutertypes_test.go +++ b/pkg/pillar/types/zedroutertypes_test.go @@ -183,56 +183,75 @@ func TestIsDPCUsable(t *testing.T) { } func TestIsDPCTestable(t *testing.T) { - n := time.Now() testMatrix := map[string]struct { devicePortConfig DevicePortConfig expectedValue bool }{ - "Difference is exactly 60 seconds": { + "DPC always failed test and not enough time passed since the last test": { devicePortConfig: DevicePortConfig{ TestResults: TestResults{ - LastFailed: n.Add(time.Second * 60), - LastSucceeded: n, + LastFailed: time.Now().Add(-2 * time.Minute), + LastSucceeded: time.Time{}, }, Ports: usablePorts, }, expectedValue: false, }, - "Difference is 61 seconds": { + "DPC succeeded, then failed and not enough time passed since then": { devicePortConfig: DevicePortConfig{ TestResults: TestResults{ - LastFailed: n.Add(time.Second * 61), - LastSucceeded: n, + LastFailed: time.Now().Add(-2 * time.Minute), + LastSucceeded: time.Now().Add(-4 * time.Minute), }, Ports: usablePorts, }, expectedValue: false, }, - "Difference is 59 seconds": { + "DPC always failed test but enough time passed since the last test": { devicePortConfig: DevicePortConfig{ TestResults: TestResults{ - LastFailed: n.Add(time.Second * 59), - LastSucceeded: n, + LastFailed: time.Now().Add(-6 * time.Minute), + LastSucceeded: time.Time{}, }, Ports: usablePorts, }, - expectedValue: false, + expectedValue: true, }, - "LastFailed is 0": { + "DPC succeeded, then failed but enough time passed since then": { + devicePortConfig: DevicePortConfig{ + TestResults: TestResults{ + LastFailed: time.Now().Add(-6 * time.Minute), + LastSucceeded: time.Now().Add(-8 * time.Minute), + }, + Ports: usablePorts, + }, + expectedValue: true, + }, + "DPC always succeeded test": { devicePortConfig: DevicePortConfig{ TestResults: TestResults{ LastFailed: time.Time{}, - LastSucceeded: n, + LastSucceeded: time.Now().Add(-2 * time.Minute), }, Ports: usablePorts, }, expectedValue: true, }, - "Last Succeeded is after Last Failed": { + "DPC failed but later succeeded test": { devicePortConfig: DevicePortConfig{ TestResults: TestResults{ - LastFailed: n, - LastSucceeded: n.Add(time.Second * 61), + LastFailed: time.Now().Add(-4 * time.Minute), + LastSucceeded: time.Now().Add(-2 * time.Minute), + }, + Ports: usablePorts, + }, + expectedValue: true, + }, + "Clocks are not synchronized": { + devicePortConfig: DevicePortConfig{ + TestResults: TestResults{ + LastFailed: time.Now().Add(time.Hour), + LastSucceeded: time.Time{}, }, Ports: usablePorts, },