From 4355487003dcc005cba94dd820174d1169986c41 Mon Sep 17 00:00:00 2001 From: Vitaly Grinberg Date: Sun, 12 Jul 2026 11:55:08 +0300 Subject: [PATCH 1/3] Calibrate delays on XR8720t A00 --- pkg/hardwareconfig/hardware-vendor/dell/XR8720t/delays.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/hardwareconfig/hardware-vendor/dell/XR8720t/delays.yaml b/pkg/hardwareconfig/hardware-vendor/dell/XR8720t/delays.yaml index b76c27b9..b4d7998f 100644 --- a/pkg/hardwareconfig/hardware-vendor/dell/XR8720t/delays.yaml +++ b/pkg/hardwareconfig/hardware-vendor/dell/XR8720t/delays.yaml @@ -52,10 +52,10 @@ connections: # NAC to Timing Module routing/wiring - from: "NAC0 phase out 1kHz" to: "DPLL phase in 1kHz" - delayPs: -5000 + delayPs: -8600 - from: "NAC0 phase out 1Hz" to: "DPLL phase in 1Hz" - delayPs: -5000 + delayPs: -8600 # DPLL to NAC (during holdover) From 34db392f6ff46ce0fceecb3083fa83b4dce4cd81 Mon Sep 17 00:00:00 2001 From: Vitaly Grinberg Date: Sun, 12 Jul 2026 12:22:24 +0300 Subject: [PATCH 2/3] Reduce log noise --- pkg/daemon/ptpdev.go | 2 +- pkg/event/event_tbc.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/daemon/ptpdev.go b/pkg/daemon/ptpdev.go index 82a2b24c..16adebbd 100644 --- a/pkg/daemon/ptpdev.go +++ b/pkg/daemon/ptpdev.go @@ -107,7 +107,7 @@ func GetDevStatusUpdate(nodePTPDev *ptpv1.NodePtpDevice) (*ptpv1.NodePtpDevice, if dev.Name == nicDefaultPort[nicBase] { ptpnetwork.LogStructuredHardwareInfo(dev.Name, dev.HardwareInfo) } else { - glog.Infof("PTP Device: %s (PCI: %s, same NIC as %s)", dev.Name, dev.HardwareInfo.PCIAddress, nicDefaultPort[nicBase]) + glog.V(14).Infof("PTP Device: %s (PCI: %s, same NIC as %s)", dev.Name, dev.HardwareInfo.PCIAddress, nicDefaultPort[nicBase]) } } diff --git a/pkg/event/event_tbc.go b/pkg/event/event_tbc.go index a2760650..be05477e 100644 --- a/pkg/event/event_tbc.go +++ b/pkg/event/event_tbc.go @@ -134,7 +134,7 @@ func (e *EventHandler) updateBCState(event EventChannel) (clockSyncState, bool) isTTSC := (e.LeadingClockData.clockID != "" && e.LeadingClockData.controlledPortsConfig == "") - glog.Info("current BC state: ", e.clkSyncState[cfgName].state) + glog.V(14).Info("current BC state: ", e.clkSyncState[cfgName].state) switch e.clkSyncState[cfgName].state { case PTP_NOTSET, PTP_FREERUN: if !e.isSourceLostBC(cfgName) && e.inSyncCondition(cfgName) { @@ -655,7 +655,7 @@ func (e *EventHandler) convergeConfig(event EventChannel) EventChannel { if event.ProcessName == PTP4lProcessName { iface := event.IFace ifacePhc := alias.GetPhcGroup(iface) - glog.Infof("convergeConfig: ptp4l iface=%s phcGroup=%q original cfgName=%s", iface, ifacePhc, event.CfgName) + glog.V(14).Infof("convergeConfig: ptp4l iface=%s phcGroup=%q original cfgName=%s", iface, ifacePhc, event.CfgName) for cfg, dd := range e.data { for _, item := range dd { if item.ProcessName != DPLL { @@ -665,12 +665,12 @@ func (e *EventHandler) convergeConfig(event EventChannel) EventChannel { dpPhc := alias.GetPhcGroup(dp.IFace) aliasMatch := alias.GetAlias(dp.IFace) == alias.GetAlias(iface) samePhc := dpPhc != "" && dpPhc == ifacePhc - glog.Infof("convergeConfig: checking DPLL iface=%s phcGroup=%q alias=%q vs ptp4l alias=%q aliasMatch=%v samePhc=%v", + glog.V(14).Infof("convergeConfig: checking DPLL iface=%s phcGroup=%q alias=%q vs ptp4l alias=%q aliasMatch=%v samePhc=%v", dp.IFace, dpPhc, alias.GetAlias(dp.IFace), alias.GetAlias(iface), aliasMatch, samePhc) if aliasMatch || samePhc { // We want to process ptp4l having a separate config with ts2phc and dpll events having ts2phc config // so in the rare occurrence of ptp4l state change we modify the event.CfgName - glog.Infof("convergeConfig: remapping ptp4l event cfgName %s -> %s (iface %s matched DPLL iface %s)", + glog.V(14).Infof("convergeConfig: remapping ptp4l event cfgName %s -> %s (iface %s matched DPLL iface %s)", event.CfgName, cfg, iface, dp.IFace) event.CfgName = cfg } From 292e8103a0533030c170f15992fdf784ed28ae09 Mon Sep 17 00:00:00 2001 From: Vitaly Grinberg Date: Mon, 13 Jul 2026 10:43:51 +0300 Subject: [PATCH 3/3] Decode DPLL FFO sint attributes as 4- or 8-byte values Kernel nla_put_sint encodes fractional-frequency-offset(-ppt) with variable width; Int32 decoding aborted pin dumps when PPT arrived as 8 bytes. Co-authored-by: Cursor --- pkg/dpll-netlink/dpll-uapi.go | 4 +-- pkg/dpll-netlink/dpll.go | 44 ++++++++++++++++++++++++---- pkg/dpll-netlink/dpll_test.go | 54 ++++++++++++++++++++++++++++------- 3 files changed, 84 insertions(+), 18 deletions(-) diff --git a/pkg/dpll-netlink/dpll-uapi.go b/pkg/dpll-netlink/dpll-uapi.go index 0f09619e..638eec94 100644 --- a/pkg/dpll-netlink/dpll-uapi.go +++ b/pkg/dpll-netlink/dpll-uapi.go @@ -400,7 +400,7 @@ type PinInfoHR struct { EsyncPulse int64 `json:"esyncPulse,omitempty"` ReferenceSync []ReferenceSync `json:"referenceSync,omitempty"` PhaseAdjustGran uint32 `json:"phaseAdjustGran,omitempty"` - FractionalFrequencyOffsetPPT int `json:"fractionalFrequencyOffsetPPT,omitempty"` + FractionalFrequencyOffsetPPT int64 `json:"fractionalFrequencyOffsetPPT,omitempty"` MeasuredFrequencyHz float64 `json:"measuredFrequencyHz,omitempty"` Operstate string `json:"operstate,omitempty"` } @@ -414,7 +414,7 @@ type PinParentDeviceHR struct { PhaseOffsetPs float64 `json:"phaseOffsetPs"` Operstate string `json:"operstate,omitempty"` FractionalFrequencyOffset int `json:"fractionalFrequencyOffset,omitempty"` - FractionalFrequencyOffsetPPT int `json:"fractionalFrequencyOffsetPPT,omitempty"` + FractionalFrequencyOffsetPPT int64 `json:"fractionalFrequencyOffsetPPT,omitempty"` } // PinParentPin contains nested netlink attributes. diff --git a/pkg/dpll-netlink/dpll.go b/pkg/dpll-netlink/dpll.go index 6baae1de..1ede2caa 100644 --- a/pkg/dpll-netlink/dpll.go +++ b/pkg/dpll-netlink/dpll.go @@ -4,6 +4,7 @@ package dpll_netlink import ( "errors" + "fmt" "log" "math" @@ -11,6 +12,21 @@ import ( "github.com/mdlayher/netlink" ) +// decodeSint decodes a netlink NLA_SINT attribute. The kernel's nla_put_sint +// encodes signed values as either 4 or 8 bytes depending on magnitude, so +// fixed-width Int32/Int64 decoders reject valid payloads. +func decodeSint(ad *netlink.AttributeDecoder) (int64, error) { + b := ad.Bytes() + switch len(b) { + case 4: + return int64(int32(ad.ByteOrder.Uint32(b))), nil + case 8: + return int64(ad.ByteOrder.Uint64(b)), nil + default: + return 0, fmt.Errorf("netlink: attribute %d is not a sint; length: %d", ad.Type(), len(b)) + } +} + // A Conn is a connection to netlink family "dpll". type Conn struct { c *genetlink.Conn @@ -331,9 +347,17 @@ func ParsePinReplies(msgs []genetlink.Message) ([]*PinInfo, error) { case DpllPinOperstate: temp.Operstate = ad.Uint32() case DpllPinFractionalFrequencyOffset: - temp.FractionalFrequencyOffset = int(ad.Int32()) + v, sintErr := decodeSint(ad) + if sintErr != nil { + return sintErr + } + temp.FractionalFrequencyOffset = int(v) case DpllPinFractionalFrequencyOffsetPPT: - temp.FractionalFrequencyOffsetPPT = int(ad.Int32()) + v, sintErr := decodeSint(ad) + if sintErr != nil { + return sintErr + } + temp.FractionalFrequencyOffsetPPT = v } } @@ -363,7 +387,11 @@ func ParsePinReplies(msgs []genetlink.Message) ([]*PinInfo, error) { case DpllPinPhaseOffset: reply.PhaseOffset = ad.Int64() case DpllPinFractionalFrequencyOffset: - reply.FractionalFrequencyOffset = int(ad.Int32()) + v, sintErr := decodeSint(ad) + if sintErr != nil { + return nil, sintErr + } + reply.FractionalFrequencyOffset = int(v) case DpllPinEsyncFrequency: reply.EsyncFrequency = ad.Int64() case DpllPinEsyncFrequencySupported: @@ -397,7 +425,11 @@ func ParsePinReplies(msgs []genetlink.Message) ([]*PinInfo, error) { case DpllPinPhaseAdjustGran: reply.PhaseAdjustGran = ad.Uint32() case DpllPinFractionalFrequencyOffsetPPT: - reply.FractionalFrequencyOffsetPPT = int(ad.Int32()) + v, sintErr := decodeSint(ad) + if sintErr != nil { + return nil, sintErr + } + reply.FractionalFrequencyOffsetPPT = v case DpllPinMeasuredFrequency: reply.MeasuredFrequency = ad.Uint64() case DpllPinOperstate: @@ -498,7 +530,7 @@ type PinInfo struct { PhaseAdjust int32 PhaseOffset int64 FractionalFrequencyOffset int - FractionalFrequencyOffsetPPT int + FractionalFrequencyOffsetPPT int64 EsyncFrequency int64 EsyncFrequencySupported []FrequencyRange EsyncPulse uint32 @@ -529,7 +561,7 @@ type PinParentDevice struct { PhaseOffset int64 Operstate uint32 FractionalFrequencyOffset int - FractionalFrequencyOffsetPPT int + FractionalFrequencyOffsetPPT int64 } // PinParentPin contains nested netlink attributes. diff --git a/pkg/dpll-netlink/dpll_test.go b/pkg/dpll-netlink/dpll_test.go index 06bbaf10..7dccc4bf 100644 --- a/pkg/dpll-netlink/dpll_test.go +++ b/pkg/dpll-netlink/dpll_test.go @@ -92,20 +92,54 @@ func Test_EncodePinControl(t *testing.T) { // TestParsePinReplies_DpllPinFractionalFrequencyOffsetPPT verifies that // ParsePinReplies correctly decodes the DpllPinFractionalFrequencyOffsetPPT // attribute (FFO in parts per trillion) into PinInfo.FractionalFrequencyOffsetPPT. +// Kernel nla_put_sint may encode as 4 or 8 bytes; both must decode. func TestParsePinReplies_DpllPinFractionalFrequencyOffsetPPT(t *testing.T) { tests := []struct { - name string - ffoPPT int32 + name string + encode func(*netlink.AttributeEncoder) + wantPPT int64 }{ - {"positive value", 12345}, - {"zero", 0}, - {"negative value", -999}, + { + name: "int32-width positive", + encode: func(ae *netlink.AttributeEncoder) { + ae.Int32(DpllPinFractionalFrequencyOffsetPPT, 12345) + }, + wantPPT: 12345, + }, + { + name: "int32-width zero", + encode: func(ae *netlink.AttributeEncoder) { + ae.Int32(DpllPinFractionalFrequencyOffsetPPT, 0) + }, + wantPPT: 0, + }, + { + name: "int32-width negative", + encode: func(ae *netlink.AttributeEncoder) { + ae.Int32(DpllPinFractionalFrequencyOffsetPPT, -999) + }, + wantPPT: -999, + }, + { + name: "int64-width value beyond int32", + encode: func(ae *netlink.AttributeEncoder) { + ae.Int64(DpllPinFractionalFrequencyOffsetPPT, 3_000_000_000) + }, + wantPPT: 3_000_000_000, + }, + { + name: "int64-width negative", + encode: func(ae *netlink.AttributeEncoder) { + ae.Int64(DpllPinFractionalFrequencyOffsetPPT, -3_000_000_000) + }, + wantPPT: -3_000_000_000, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ae := netlink.NewAttributeEncoder() ae.Uint32(DpllPinID, 1) - ae.Int32(DpllPinFractionalFrequencyOffsetPPT, tt.ffoPPT) + tt.encode(ae) payload, err := ae.Encode() assert.NoError(t, err, "encode attributes") @@ -113,7 +147,7 @@ func TestParsePinReplies_DpllPinFractionalFrequencyOffsetPPT(t *testing.T) { replies, err := ParsePinReplies(msgs) assert.NoError(t, err) assert.Len(t, replies, 1) - assert.Equal(t, int(tt.ffoPPT), replies[0].FractionalFrequencyOffsetPPT, + assert.Equal(t, tt.wantPPT, replies[0].FractionalFrequencyOffsetPPT, "FractionalFrequencyOffsetPPT should match encoded value") }) } @@ -249,7 +283,7 @@ func TestParsePinReplies_ParentDeviceNewFields(t *testing.T) { const parentID = uint32(7) const operstate = uint32(PinOperstateActive) const ffo = int32(-42) - const ffoPPT = int32(12345) + const ffoPPT = int64(3_000_000_000) ae := netlink.NewAttributeEncoder() ae.Uint32(DpllPinID, 1) @@ -257,7 +291,7 @@ func TestParsePinReplies_ParentDeviceNewFields(t *testing.T) { nae.Uint32(DpllPinParentID, parentID) nae.Uint32(DpllPinOperstate, operstate) nae.Int32(DpllPinFractionalFrequencyOffset, ffo) - nae.Int32(DpllPinFractionalFrequencyOffsetPPT, ffoPPT) + nae.Int64(DpllPinFractionalFrequencyOffsetPPT, ffoPPT) return nil }) payload, err := ae.Encode() @@ -272,5 +306,5 @@ func TestParsePinReplies_ParentDeviceNewFields(t *testing.T) { assert.Equal(t, parentID, pd.ParentID) assert.Equal(t, operstate, pd.Operstate) assert.Equal(t, int(ffo), pd.FractionalFrequencyOffset) - assert.Equal(t, int(ffoPPT), pd.FractionalFrequencyOffsetPPT) + assert.Equal(t, ffoPPT, pd.FractionalFrequencyOffsetPPT) }