diff --git a/pkg/daemon/daemon.go b/pkg/daemon/daemon.go index 571deb69..bc0a8622 100644 --- a/pkg/daemon/daemon.go +++ b/pkg/daemon/daemon.go @@ -791,6 +791,8 @@ func (dn *Daemon) applyNodePtpProfile(runID int, nodeProfile *ptpv1.PtpProfile) if controllingProfile, isControlled := (*nodeProfile).PtpSettings["controllingProfile"]; isControlled && controllingProfile != "" { // See DownstreamIWF glog.Infof("Skipping PMC monitoring for controlled profile %s", *nodeProfile.Name) + } else if clockType == event.GM { + glog.Infof("Skipping PMC monitoring for GM") } else { pmcClockType, clockTypeFound := (*nodeProfile).PtpSettings["clockType"] if !clockTypeFound { diff --git a/pkg/event/event.go b/pkg/event/event.go index 7e30169a..530dbc03 100644 --- a/pkg/event/event.go +++ b/pkg/event/event.go @@ -644,25 +644,28 @@ connect: case <-e.closeCh: return case <-classTicker.C: // send clock class event 60 secs interval - if cfgName != "" { - parts := strings.SplitN(cfgName, ".", 2) + for clkCfgName, data := range e.clkSyncState { + clockClass := data.clockClass + parts := strings.SplitN(clkCfgName, ".", 2) if len(parts) >= 2 { - cfgName = "ptp4l." + strings.Join(parts[1:], ".") + clkCfgName = "ptp4l." + strings.Join(parts[1:], ".") } - utils.EmitClockClass(c, PTP4lProcessName, cfgName, e.clockClass) + if clockClass == 0 { + continue + } + if clkCfgName == cfgName { + // Stop double emit + cfgName = "" + } + utils.EmitClockClass(c, PTP4lProcessName, clkCfgName, clockClass) } - for cfgName, data := range e.clkSyncState { - clockClass := data.clockClass + if cfgName != "" { parts := strings.SplitN(cfgName, ".", 2) if len(parts) >= 2 { cfgName = "ptp4l." + strings.Join(parts[1:], ".") } - if clockClass == 0 { - parentDS, _ := pmc.RunPMCExpGetParentDS(cfgName, true) - clockClass = fbprotocol.ClockClass(parentDS.GrandmasterClockClass) - } - utils.EmitClockClass(c, PTP4lProcessName, cfgName, clockClass) + utils.EmitClockClass(c, PTP4lProcessName, cfgName, e.clockClass) } } } diff --git a/pkg/event/event_internal_test.go b/pkg/event/event_internal_test.go index a3cee59f..d0602a5c 100644 --- a/pkg/event/event_internal_test.go +++ b/pkg/event/event_internal_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/k8snetworkplumbingwg/linuxptp-daemon/pkg/utils" "github.com/stretchr/testify/assert" ) @@ -274,6 +275,7 @@ func TestGetLargestOffset(t *testing.T) { cfgName string data map[string][]*Data clkSyncState map[string]*clockSyncState + fillWindow bool expected int64 }{ { @@ -306,6 +308,24 @@ func TestGetLargestOffset(t *testing.T) { }, expected: FaultyPhaseOffset, }, + { + name: "Window not full - should return FaultyPhaseOffset", + cfgName: "test", + data: map[string][]*Data{ + "test": { + {ProcessName: DPLL, Details: []*DataDetails{ + {IFace: "eth0", Offset: 15, time: recentTime}, + {IFace: "eth1", Offset: 5, time: recentTime}, + }}, + }, + }, + clkSyncState: map[string]*clockSyncState{ + "test": { + leadingIFace: "eth99", + }, + }, + expected: FaultyPhaseOffset, + }, { name: "Single offset value", cfgName: "test", @@ -321,7 +341,8 @@ func TestGetLargestOffset(t *testing.T) { leadingIFace: "eth99", }, }, - expected: 100, + fillWindow: true, + expected: 100, }, { name: "Multiple offsets - largest positive", @@ -340,7 +361,8 @@ func TestGetLargestOffset(t *testing.T) { leadingIFace: "eth99", }, }, - expected: 25, + fillWindow: true, + expected: 25, }, { name: "Multiple offsets - largest negative", @@ -359,7 +381,8 @@ func TestGetLargestOffset(t *testing.T) { leadingIFace: "eth99", }, }, - expected: -30, + fillWindow: true, + expected: -30, }, { name: "Mixed positive and negative - largest absolute value", @@ -378,7 +401,8 @@ func TestGetLargestOffset(t *testing.T) { leadingIFace: "eth99", }, }, - expected: -25, + fillWindow: true, + expected: -25, }, { name: "Stale data filtered out", @@ -397,7 +421,8 @@ func TestGetLargestOffset(t *testing.T) { leadingIFace: "eth99", }, }, - expected: 20, + fillWindow: true, + expected: 20, }, { name: "All data stale - should return FaultyPhaseOffset", @@ -439,7 +464,8 @@ func TestGetLargestOffset(t *testing.T) { leadingIFace: "eth99", }, }, - expected: -40, + fillWindow: true, + expected: -40, }, { name: "Zero offset values", @@ -457,7 +483,8 @@ func TestGetLargestOffset(t *testing.T) { leadingIFace: "eth99", }, }, - expected: 0, + fillWindow: true, + expected: 0, }, { name: "Mix of zero and non-zero offsets", @@ -476,12 +503,27 @@ func TestGetLargestOffset(t *testing.T) { leadingIFace: "eth99", }, }, - expected: 10, + fillWindow: true, + expected: 10, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + if tt.fillWindow { + for _, processData := range tt.data { + for _, d := range processData { + if len(d.Details) == 0 { + continue + } + d.window = *utils.NewWindow(WindowSize) + for i := 0; i < WindowSize; i++ { + offset := d.Details[i%len(d.Details)].Offset + d.window.Insert(float64(offset)) + } + } + } + } e := EventHandler{data: tt.data, clkSyncState: tt.clkSyncState} result := e.getLargestOffset(tt.cfgName) assert.Equal(t, tt.expected, result) diff --git a/pkg/event/event_tbc.go b/pkg/event/event_tbc.go index f5081567..6c30f43b 100644 --- a/pkg/event/event_tbc.go +++ b/pkg/event/event_tbc.go @@ -126,6 +126,9 @@ func (e *EventHandler) updateBCState(event EventChannel, c net.Conn) clockSyncSt e.clkSyncState[cfgName].state) return *e.clkSyncState[cfgName] } + + isTTSC := (e.LeadingClockData.clockID != "" && e.LeadingClockData.controlledPortsConfig == "") + glog.Info("current BC state: ", e.clkSyncState[cfgName].state) switch e.clkSyncState[cfgName].state { case PTP_NOTSET, PTP_FREERUN: @@ -156,7 +159,9 @@ func (e *EventHandler) updateBCState(event EventChannel, c net.Conn) clockSyncSt e.LeadingClockData.downstreamParentDataSet = e.LeadingClockData.upstreamParentDataSet updateDownstreamData = true } - if e.clkSyncState[cfgName].clockClass != fbprotocol.ClockClass(e.LeadingClockData.upstreamParentDataSet.GrandmasterClockClass) { + if e.LeadingClockData.upstreamParentDataSet.GrandmasterClockClass == uint8(protocol.ClockClassFreerun) { + updateDownstreamData = false // Don't propagate uptream free run and instead let future call move to holdover/freerun + } else if e.clkSyncState[cfgName].clockClass != fbprotocol.ClockClass(e.LeadingClockData.upstreamParentDataSet.GrandmasterClockClass) && !isTTSC { e.clkSyncState[cfgName].clockClass = fbprotocol.ClockClass(e.LeadingClockData.upstreamParentDataSet.GrandmasterClockClass) e.clkSyncState[cfgName].clockAccuracy = fbprotocol.ClockAccuracy(e.LeadingClockData.upstreamParentDataSet.GrandmasterClockAccuracy) } @@ -214,8 +219,15 @@ func (e *EventHandler) updateBCState(event EventChannel, c net.Conn) clockSyncSt e.clkSyncState[cfgName].clockOffset = e.getLargestOffset(cfgName) } - if updateDownstreamData { - go e.updateDownstreamData(cfgName, c) + if isTTSC && e.clkSyncState[cfgName].clockClass != fbprotocol.ClockClassSlaveOnly { + e.clkSyncState[cfgName].clockClass = fbprotocol.ClockClassSlaveOnly + } + if updateDownstreamData && e.clkSyncState[cfgName].clockClass != protocol.ClockClassUninitialized { + if isTTSC { + e.announceClockClass(e.clkSyncState[cfgName].clockClass, e.clkSyncState[cfgName].clockAccuracy, cfgName, c) + } else { + go e.updateDownstreamData(cfgName, c) + } } // this will reduce log noise and prints 1 per sec logTime := time.Now().Unix() @@ -427,6 +439,10 @@ func (e *EventHandler) getLargestOffset(cfgName string) int64 { if dd.time < staleTime { continue } + if !d.window.IsFull() { + glog.Info("Largest offset ", FaultyPhaseOffset) + return FaultyPhaseOffset + } if worstOffset == FaultyPhaseOffset { if dd.IFace == e.clkSyncState[cfgName].leadingIFace { worstOffset = int64(d.window.Mean())