@@ -25,6 +25,7 @@ import (
2525 "github.com/k8snetworkplumbingwg/linuxptp-daemon/pkg/config"
2626
2727 "github.com/k8snetworkplumbingwg/linuxptp-daemon/pkg/dpll"
28+ dpllnl "github.com/k8snetworkplumbingwg/linuxptp-daemon/pkg/dpll-netlink"
2829 "github.com/k8snetworkplumbingwg/linuxptp-daemon/pkg/leap"
2930
3031 "github.com/k8snetworkplumbingwg/linuxptp-daemon/pkg/event"
@@ -336,6 +337,57 @@ func (dn *Daemon) getHoldoverParameters(profileName string, clockID uint64) *ptp
336337 return dn .hardwareConfigManager .GetHoldoverParameters (profileName , clockID )
337338}
338339
340+ // getInterfacesFromHardwareConfig derives interfaces from hardwareconfig structure for T-BC mode.
341+ // It extracts the first interface from structure[*]->dpll->networkInterface.
342+ // Returns an empty slice if no hardwareconfig is available or no interfaces are found.
343+ func (dn * Daemon ) getInterfacesFromHardwareConfig (nodeProfile * ptpv1.PtpProfile ) config.IFaces {
344+ if dn .hardwareConfigManager == nil || nodeProfile == nil || nodeProfile .Name == nil {
345+ return config.IFaces {}
346+ }
347+
348+ // Get hardware configs for this profile
349+ hwProfiles := dn .hardwareConfigManager .GetHardwareConfigsForProfile (nodeProfile )
350+ if len (hwProfiles ) == 0 {
351+ glog .V (2 ).Infof ("No hardware configs found for profile %s" , * nodeProfile .Name )
352+ return config.IFaces {}
353+ }
354+
355+ var interfaces config.IFaces
356+
357+ // Iterate through hardware profiles and extract interfaces from structure
358+ for _ , hwProfile := range hwProfiles {
359+ if hwProfile .ClockChain == nil || len (hwProfile .ClockChain .Structure ) == 0 {
360+ continue
361+ }
362+
363+ // Get the first subsystem from structure and use GetSubsystemNetworkInterface
364+ firstSubsystem := hwProfile .ClockChain .Structure [0 ]
365+ networkInterface , err := hardwareconfig .GetSubsystemNetworkInterface (hwProfile .ClockChain , firstSubsystem .Name )
366+ if err != nil {
367+ glog .V (2 ).Infof ("Failed to get network interface for first subsystem %s: %v" , firstSubsystem .Name , err )
368+ continue
369+ }
370+
371+ if networkInterface != "" {
372+ // Determine event source based on T-BC configuration
373+ // For T-BC, the interface typically depends on PTP4l
374+ eventSource := event .PTP4l
375+
376+ // Get PHC ID for the interface
377+ phcID := ptpnetwork .GetPhcId (networkInterface )
378+
379+ interfaces = append (interfaces , config.Iface {
380+ Name : networkInterface ,
381+ Source : eventSource ,
382+ PhcId : phcID ,
383+ IsMaster : false ,
384+ })
385+ }
386+ }
387+
388+ return interfaces
389+ }
390+
339391// New LinuxPTP is called by daemon to generate new linuxptp instance
340392func New (
341393 nodeName string ,
@@ -450,6 +502,7 @@ func (dn *Daemon) applyNodePTPProfiles() error {
450502 dn .readyTracker .setConfig (false )
451503
452504 glog .Infof ("in applyNodePTPProfiles - starting to apply %d node profiles" , len (dn .ptpUpdate .NodeProfiles ))
505+
453506 dn .stopAllProcesses ()
454507 // All process should have been stopped,
455508 // clear process in process manager.
@@ -485,6 +538,20 @@ func (dn *Daemon) applyNodePTPProfiles() error {
485538 })
486539
487540 relations := reconcileRelatedProfiles (dn .ptpUpdate .NodeProfiles )
541+
542+ // Update PtpConfig in hardware config manager for clock chain resolution
543+ // This is done after sorting and reconciliation to ensure we use the same
544+ // processed profiles that will actually be applied. The NodeProfiles are already
545+ // filtered to be relevant for this node by calculateNodeProfiles in the controller.
546+ if dn .hardwareConfigManager != nil && len (dn .ptpUpdate .NodeProfiles ) > 0 {
547+ ptpConfig := & ptpv1.PtpConfig {
548+ Spec : ptpv1.PtpConfigSpec {
549+ Profile : dn .ptpUpdate .NodeProfiles ,
550+ },
551+ }
552+ dn .hardwareConfigManager .SetPtpConfig (ptpConfig )
553+ glog .Infof ("Updated PtpConfig in hardware config manager with %d profiles (after sorting and reconciliation)" , len (dn .ptpUpdate .NodeProfiles ))
554+ }
488555 // TODO: resolve clock IDs, clockType, leadingInterface and upstreamPort from hardware config
489556 // (needed to keep code compatibility elsewhere and allow it to work both with hardware config and plugins)
490557 for _ , profile := range dn .ptpUpdate .NodeProfiles {
@@ -920,7 +987,24 @@ func (dn *Daemon) applyNodePtpProfile(runID int, nodeProfile *ptpv1.PtpProfile)
920987 }
921988 var clockId uint64
922989 phaseOffsetPinFilter := map [string ]string {}
923- for _ , iface := range dprocess .ifaces {
990+
991+ // For T-BC mode with hardwareconfig, derive interfaces from hardwareconfig structure
992+ // instead of analyzing ts2phc configuration file
993+ var interfacesToUse config.IFaces
994+ if profileClockType == TBC && dn .hardwareConfigManager != nil &&
995+ dn .hardwareConfigManager .ReadyHardwareConfigForProfile (* nodeProfile .Name ) {
996+ interfacesToUse = dn .getInterfacesFromHardwareConfig (nodeProfile )
997+ if len (interfacesToUse ) > 0 {
998+ glog .Infof ("Using interfaces from hardwareconfig for T-BC profile %s: %v" , * nodeProfile .Name , interfacesToUse )
999+ } else {
1000+ glog .Warningf ("Failed to derive interfaces from hardwareconfig for T-BC profile %s, falling back to ts2phc config" , * nodeProfile .Name )
1001+ interfacesToUse = dprocess .ifaces
1002+ }
1003+ } else {
1004+ interfacesToUse = dprocess .ifaces
1005+ }
1006+
1007+ for _ , iface := range interfacesToUse {
9241008 var eventSource []event.EventSource
9251009 if iface .Source == event .GNSS || iface .Source == event .PPS ||
9261010 (iface .Source == event .PTP4l && profileClockType == TBC ) {
@@ -986,6 +1070,12 @@ func (dn *Daemon) applyNodePtpProfile(runID int, nodeProfile *ptpv1.PtpProfile)
9861070 // Used only in T-BC in-sync condition:
9871071 inSyncConditionTh , inSyncConditionTimes )
9881072 glog .Infof ("depending on %s" , dpllDaemon .DependsOn ())
1073+ // Set hardwareconfig handler if hardwareconfig manager is available
1074+ if dn .hardwareConfigManager != nil {
1075+ dpllDaemon .SetHardwareConfigHandler (func (devices []* dpllnl.DoDeviceGetReply ) error {
1076+ return dn .hardwareConfigManager .ProcessDPLLDeviceNotifications (devices )
1077+ })
1078+ }
9891079 dpllDaemon .CmdInit ()
9901080 dprocess .depProcess = append (dprocess .depProcess , dpllDaemon )
9911081 }
@@ -1097,14 +1187,29 @@ func (p *ptpProcess) tBCTransitionCheck(output string, pm *plugin.PluginManager)
10971187}
10981188
10991189// applyConditionOrFallback applies hardware config for a condition or falls back to plugin
1100- func (p * ptpProcess ) applyConditionOrFallback (conditionType , pluginAction string , pm * plugin.PluginManager ) {
1190+ func (p * ptpProcess ) applyConditionOrFallback (conditionType , pluginAction string , pm * plugin.PluginManager , logLine string ) {
11011191 if p .dn != nil && p .dn .hardwareConfigManager != nil {
1102- if err := p .dn .hardwareConfigManager .ApplyConditionForProfile (& p .nodeProfile , conditionType ); err != nil {
1103- glog .Errorf ("Failed to apply hardware config for '%s' condition: %v" , conditionType , err )
1192+ // Extract source name from log line if available
1193+ sourceName := ""
1194+ if p .tbcStateDetector != nil && logLine != "" {
1195+ portName := p .tbcStateDetector .ExtractPortName (logLine )
1196+ if portName != "" {
1197+ // Look up source name(s) for this port
1198+ sources := p .tbcStateDetector .GetSourcesForPort (portName )
1199+ if len (sources ) > 0 {
1200+ // Use the first matching source (typically there's only one)
1201+ sourceName = sources [0 ]
1202+ glog .Infof ("Found source '%s' for port '%s'" , sourceName , portName )
1203+ }
1204+ }
1205+ }
1206+
1207+ if err := p .dn .hardwareConfigManager .ApplyConditionForProfile (& p .nodeProfile , conditionType , sourceName ); err != nil {
1208+ glog .Errorf ("Failed to apply hardware config for '%s' condition (source=%s): %v" , conditionType , sourceName , err )
11041209 // Fallback to plugin if hardware config fails
11051210 pm .AfterRunPTPCommand (& p .nodeProfile , pluginAction )
11061211 } else {
1107- glog .Infof ("Successfully applied hardware config for '%s' condition" , conditionType )
1212+ glog .Infof ("Successfully applied hardware config for '%s' condition (source=%s) " , conditionType , sourceName )
11081213 }
11091214 } else {
11101215 // Fallback to plugin if no hardware config manager
@@ -1119,11 +1224,11 @@ func (p *ptpProcess) processTBCTransitionHardwareConfig(output string, pm *plugi
11191224
11201225 switch conditionType {
11211226 case hardwareconfig .ConditionTypeLocked :
1122- p .applyConditionOrFallback (hardwareconfig .ConditionTypeLocked , "tbc-ho-exit" , pm )
1227+ p .applyConditionOrFallback (hardwareconfig .ConditionTypeLocked , "tbc-ho-exit" , pm , output )
11231228 p .lastTransitionResult = event .PTP_LOCKED
11241229 p .sendPtp4lEvent ()
11251230 case hardwareconfig .ConditionTypeLost :
1126- p .applyConditionOrFallback (hardwareconfig .ConditionTypeLost , "tbc-ho-entry" , pm )
1231+ p .applyConditionOrFallback (hardwareconfig .ConditionTypeLost , "tbc-ho-entry" , pm , output )
11271232 p .lastTransitionResult = event .PTP_FREERUN
11281233 p .sendPtp4lEvent ()
11291234 }
0 commit comments