From 7e33d11168e06865eb40b55ccf7348aca5c6214a Mon Sep 17 00:00:00 2001 From: nocturnalastro Date: Mon, 23 Feb 2026 16:26:29 +0000 Subject: [PATCH 1/3] Add simple alias sub package --- plugins/ptp_operator/alias/alias.go | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 plugins/ptp_operator/alias/alias.go diff --git a/plugins/ptp_operator/alias/alias.go b/plugins/ptp_operator/alias/alias.go new file mode 100644 index 00000000..33caccaf --- /dev/null +++ b/plugins/ptp_operator/alias/alias.go @@ -0,0 +1,37 @@ +package alias + +import "sync" + +type store struct { + sync.RWMutex + aliases map[string]string +} + +var storeInstance = store{aliases: make(map[string]string)} + +// GetAlias returns the alias for the given interface name, or the +// interface name itself when no alias has been registered. +func GetAlias(ifname string) string { + storeInstance.RLock() + defer storeInstance.RUnlock() + if v, ok := storeInstance.aliases[ifname]; ok { + return v + } + return ifname +} + +// SetAlias records an alias for the given interface name. +func SetAlias(ifname, alias string) { + storeInstance.Lock() + defer storeInstance.Unlock() + storeInstance.aliases[ifname] = alias +} + +// Debug logs every registered alias through the supplied logger function. +func Debug(logF func(string, ...any)) { + storeInstance.RLock() + defer storeInstance.RUnlock() + for ifName, a := range storeInstance.aliases { + logF("DEBUG: ifname: '%s' alias: '%s'\n", ifName, a) + } +} From 9166354d28151b72b75c8b3c4e915b40026ae4a6 Mon Sep 17 00:00:00 2001 From: nocturnalastro Date: Thu, 23 Oct 2025 16:07:38 +0100 Subject: [PATCH 2/3] Fetch aliases from ptp4l config produces by linuxptp-daemon --- plugins/ptp_operator/event/event.go | 18 ++--- plugins/ptp_operator/metrics/alias_sync.go | 33 ++++++++++ plugins/ptp_operator/metrics/logparser.go | 65 +++++++++---------- plugins/ptp_operator/metrics/metrics.go | 59 +++++++++-------- plugins/ptp_operator/ptp4lconf/ptp4lConfig.go | 10 ++- plugins/ptp_operator/ptp_operator_plugin.go | 5 ++ plugins/ptp_operator/utils/utils.go | 50 -------------- plugins/ptp_operator/utils/utils_test.go | 50 -------------- 8 files changed, 115 insertions(+), 175 deletions(-) create mode 100644 plugins/ptp_operator/metrics/alias_sync.go delete mode 100644 plugins/ptp_operator/utils/utils.go delete mode 100644 plugins/ptp_operator/utils/utils_test.go diff --git a/plugins/ptp_operator/event/event.go b/plugins/ptp_operator/event/event.go index e26c804c..72c65938 100644 --- a/plugins/ptp_operator/event/event.go +++ b/plugins/ptp_operator/event/event.go @@ -19,7 +19,7 @@ import ( "sync" "github.com/prometheus/client_golang/prometheus" - "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/utils" + "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/alias" "github.com/redhat-cne/sdk-go/pkg/event/ptp" log "github.com/sirupsen/logrus" "k8s.io/utils/pointer" @@ -125,11 +125,11 @@ func (p *PTPEventState) UpdateCurrentEventState(c ClockState, metrics map[string } if clockState.IFace != nil { iface := *clockState.IFace - alias := utils.GetAlias(iface) + aliasValue := alias.GetAlias(iface) for k, v := range c.Value { if clockState.Metric[k].metricGauge != nil { clockState.Metric[k].metricGauge.With(map[string]string{"from": clockState.Process, "process": clockState.Process, - "node": clockState.NodeName, "iface": alias}).Set(float64(v)) + "node": clockState.NodeName, "iface": aliasValue}).Set(float64(v)) } else { log.Infof("metric object was not found for %s=%s", iface, k) } @@ -190,9 +190,9 @@ func (p *PTPEventState) UpdateCurrentEventState(c ClockState, metrics map[string if clockState.IFace != nil { iface = *clockState.IFace } - alias := utils.GetAlias(iface) + aliasValue := alias.GetAlias(iface) metrics[k].metricGauge.With(map[string]string{"from": clockState.Process, "process": clockState.Process, - "node": clockState.NodeName, "iface": alias}).Set(float64(v)) + "node": clockState.NodeName, "iface": aliasValue}).Set(float64(v)) } clockState.Metric = metrics p.DependsOn[clockState.Process] = []*ClockState{clockState} @@ -269,21 +269,21 @@ func (p *PTPEventState) DeleteAllMetrics(m []*prometheus.GaugeVec) { if dd.IFace == nil { continue } - alias := utils.GetAlias(*dd.IFace) + aliasValue := alias.GetAlias(*dd.IFace) if dd.Metric != nil { // unregister metric for _, v := range dd.Metric { if v.metricGauge != nil && dd.IFace != nil { - v.metricGauge.Delete(prometheus.Labels{"process": dd.Process, "iface": alias, "node": dd.NodeName}) + v.metricGauge.Delete(prometheus.Labels{"process": dd.Process, "iface": aliasValue, "node": dd.NodeName}) prometheus.Unregister(v.metricGauge) } } for _, mm := range m { mm.Delete(prometheus.Labels{ - "process": dd.Process, "from": dd.Process, "node": dd.NodeName, "iface": alias}) + "process": dd.Process, "from": dd.Process, "node": dd.NodeName, "iface": aliasValue}) // find metrics without from - click clock state mm.Delete(prometheus.Labels{ - "process": dd.Process, "node": dd.NodeName, "iface": alias}) + "process": dd.Process, "node": dd.NodeName, "iface": aliasValue}) } } delete(p.DependsOn, dd.Process) diff --git a/plugins/ptp_operator/metrics/alias_sync.go b/plugins/ptp_operator/metrics/alias_sync.go new file mode 100644 index 00000000..a8719c59 --- /dev/null +++ b/plugins/ptp_operator/metrics/alias_sync.go @@ -0,0 +1,33 @@ +package metrics + +import ( + "encoding/json" + "net/http" + "time" + + "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/alias" + log "github.com/sirupsen/logrus" +) + +const portAliasesEndpoint = "http://localhost:8081/port-aliases" + +// SyncAliasesFromDaemon fetches aliases from linuxptp-daemon and populates the local alias store +func SyncAliasesFromDaemon() error { + client := &http.Client{Timeout: 2 * time.Second} + resp, err := client.Get(portAliasesEndpoint) + if err != nil { + return err + } + defer resp.Body.Close() + + var aliases map[string]string + if err = json.NewDecoder(resp.Body).Decode(&aliases); err != nil { + return err + } + + for ifName, aliasValue := range aliases { + alias.SetAlias(ifName, aliasValue) + } + log.Infof("Synced %d port aliases from linuxptp-daemon", len(aliases)) + return nil +} diff --git a/plugins/ptp_operator/metrics/logparser.go b/plugins/ptp_operator/metrics/logparser.go index cf987710..2f515997 100644 --- a/plugins/ptp_operator/metrics/logparser.go +++ b/plugins/ptp_operator/metrics/logparser.go @@ -6,14 +6,13 @@ import ( "strconv" "strings" + "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/alias" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/event" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/stats" - "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/utils" - "k8s.io/utils/pointer" - "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/types" "github.com/redhat-cne/sdk-go/pkg/event/ptp" log "github.com/sirupsen/logrus" + "k8s.io/utils/pointer" ) var ( @@ -385,17 +384,17 @@ func (p *PTPEventManager) ParseGMLogs(processName, configName, output string, fi Metric: nil, NodeName: ptpNodeName, } - alias := ptpStats[masterType].Alias() - if alias == "" { - alias = utils.GetAlias(iface) - ptpStats[masterType].SetAlias(alias) + aliasValue := ptpStats[masterType].Alias() + if aliasValue == "" { + aliasValue = alias.GetAlias(iface) + ptpStats[masterType].SetAlias(aliasValue) } - SyncState.With(map[string]string{"process": processName, "node": ptpNodeName, "iface": alias}).Set(GetSyncStateID(syncState)) + SyncState.With(map[string]string{"process": processName, "node": ptpNodeName, "iface": aliasValue}).Set(GetSyncStateID(syncState)) // status metrics ptpStats[masterType].SetPtpDependentEventState(clockState, ptpStats.HasMetrics(processName), ptpStats.HasMetricHelp(processName)) // If GM is locked/Freerun/Holdover then ptp state change event - masterResource := fmt.Sprintf("%s/%s", alias, MasterClockType) + masterResource := fmt.Sprintf("%s/%s", aliasValue, MasterClockType) lastClockState := ptpStats[masterType].LastSyncState() // When GM is enabled, there is only one event happening at the GM level for now, so it is not being sent to the state decision routine. @@ -413,8 +412,8 @@ func (p *PTPEventManager) ParseGMLogs(processName, configName, output string, fi log.Infof("%s sync state %s, last ptp state is : %s", masterResource, clockState.State, lastClockState) ptpStats[masterType].SetLastSyncState(clockState.State) p.PublishEvent(clockState.State, lastOffset, masterResource, ptp.PtpStateChange) - UpdateSyncStateMetrics(processName, alias, ptpStats[masterType].LastSyncState()) - UpdatePTPOffsetMetrics(processName, processName, alias, float64(lastOffset)) + UpdateSyncStateMetrics(processName, aliasValue, ptpStats[masterType].LastSyncState()) + UpdatePTPOffsetMetrics(processName, processName, aliasValue, float64(lastOffset)) } } @@ -459,10 +458,10 @@ func (p *PTPEventManager) ParseTBCLogs(processName, configName, output string, f tbcClockNameType := types.IFace(stats.TBCMainClockName) - alias := ptpStats[tbcClockNameType].Alias() - if alias == "" { - alias = utils.GetAlias(iface) - ptpStats[tbcClockNameType].SetAlias(alias) + aliasValue := ptpStats[tbcClockNameType].Alias() + if aliasValue == "" { + aliasValue = alias.GetAlias(iface) + ptpStats[tbcClockNameType].SetAlias(aliasValue) } clockState := event.ClockState{ @@ -475,18 +474,18 @@ func (p *PTPEventManager) ParseTBCLogs(processName, configName, output string, f NodeName: ptpNodeName, } - SyncState.With(map[string]string{"process": processName, "node": ptpNodeName, "iface": alias}).Set(GetSyncStateID(syncState)) + SyncState.With(map[string]string{"process": processName, "node": ptpNodeName, "iface": aliasValue}).Set(GetSyncStateID(syncState)) // status metrics ptpStats[tbcClockNameType].SetPtpDependentEventState(clockState, ptpStats.HasMetrics(processName), ptpStats.HasMetricHelp(processName)) // If GM is locked/Freerun/Holdover then ptp state change event - masterResource := fmt.Sprintf("%s/%s", alias, MasterClockType) + masterResource := fmt.Sprintf("%s/%s", aliasValue, MasterClockType) lastClockState := ptpStats[tbcClockNameType].LastSyncState() ptpStats[tbcClockNameType].SetLastOffset(offs) lastOffset := ptpStats[tbcClockNameType].LastOffset() // Update the T-BC offset metric on every status report - UpdatePTPOffsetMetrics(processName, processName, alias, float64(lastOffset)) + UpdatePTPOffsetMetrics(processName, processName, aliasValue, float64(lastOffset)) if clockState.State != lastClockState && clockState.State != "" { // publish directly here log.Infof("%s sync state %s, last ptp state is : %s", masterResource, clockState.State, lastClockState) @@ -494,12 +493,12 @@ func (p *PTPEventManager) ParseTBCLogs(processName, configName, output string, f p.PublishEvent(clockState.State, lastOffset, masterResource, ptp.PtpStateChange) } - UpdateSyncStateMetrics(processName, alias, ptpSyncState) + UpdateSyncStateMetrics(processName, aliasValue, ptpSyncState) // Impose T-BC state onto the ts2phc process state for the upstream interface // This is needed because ts2phc doesn't update the upstream interface // when ptp4l updates it in the T-BC mode - UpdateSyncStateMetrics(ts2phcProcessName, alias, ptpSyncState) + UpdateSyncStateMetrics(ts2phcProcessName, aliasValue, ptpSyncState) // if there is phc2sys ooptions enabled then when the clock is FREERUN annouce OSCLOCK as FREERUN if clockState.State == ptp.FREERUN { @@ -574,10 +573,10 @@ logStatusLoop: } if err == nil { - alias := ptpStats[ifaceType].Alias() - if alias == "" { - alias = utils.GetAlias(*iface) - ptpStats[ifaceType].SetAlias(alias) + aliasValue := ptpStats[ifaceType].Alias() + if aliasValue == "" { + aliasValue = alias.GetAlias(*iface) + ptpStats[ifaceType].SetAlias(aliasValue) } ptpStats[ifaceType].SetPtpDependentEventState(event.ClockState{ State: GetSyncState(syncState), @@ -594,8 +593,8 @@ logStatusLoop: ppsStatus: "0=UNAVAILABLE, 1=AVAILABLE", }, }, ptpStats.HasMetrics(processName), ptpStats.HasMetricHelp(processName)) - SyncState.With(map[string]string{"process": processName, "node": ptpNodeName, "iface": alias}).Set(GetSyncStateID(syncState)) - UpdatePTPOffsetMetrics(processName, processName, alias, dpllOffset) + SyncState.With(map[string]string{"process": processName, "node": ptpNodeName, "iface": aliasValue}).Set(GetSyncStateID(syncState)) + UpdatePTPOffsetMetrics(processName, processName, aliasValue, dpllOffset) } else { log.Errorf("error parsing dpll %s", err.Error()) } @@ -635,17 +634,17 @@ func (p *PTPEventManager) ParseGNSSLogs(processName, configName, output string, //openshift_ptp_offset_ns{from="gnss",iface="ens2f1",node="cnfde21.ptp.lab.eng.bos.redhat.com",process="gnss"} 0 if err == nil { - alias := ptpStats[ifaceType].Alias() - if alias == "" { - alias = utils.GetAlias(*iface) - ptpStats[ifaceType].SetAlias(alias) + aliasValue := ptpStats[ifaceType].Alias() + if aliasValue == "" { + aliasValue = alias.GetAlias(*iface) + ptpStats[ifaceType].SetAlias(aliasValue) } // last state of GNSS lastState, errState := ptpStats[ifaceType].GetStateState(processName, iface) pLabels := map[string]string{"from": processName, "node": ptpNodeName, - "process": processName, "iface": alias} + "process": processName, "iface": aliasValue} PtpOffset.With(pLabels).Set(gnssOffset) - SyncState.With(map[string]string{"process": processName, "node": ptpNodeName, "iface": alias}).Set(GetSyncStateID(syncState)) + SyncState.With(map[string]string{"process": processName, "node": ptpNodeName, "iface": aliasValue}).Set(GetSyncStateID(syncState)) ptpStats[ifaceType].SetPtpDependentEventState(event.ClockState{ State: GetSyncState(syncState), Offset: pointer.Float64(gnssOffset), @@ -659,7 +658,7 @@ func (p *PTPEventManager) ParseGNSSLogs(processName, configName, output string, // reduce noise ; if state changed then send events if lastState != GetSyncState(syncState) || errState != nil { log.Infof("%s last state %s and current state %s", processName, lastState, GetSyncState(syncState)) - masterResource := fmt.Sprintf("%s/%s", alias, MasterClockType) + masterResource := fmt.Sprintf("%s/%s", aliasValue, MasterClockType) p.publishGNSSEvent(gnssState, gnssOffset, GetSyncState(syncState), masterResource, ptp.GnssStateChange) } } diff --git a/plugins/ptp_operator/metrics/metrics.go b/plugins/ptp_operator/metrics/metrics.go index d49a8105..67586170 100644 --- a/plugins/ptp_operator/metrics/metrics.go +++ b/plugins/ptp_operator/metrics/metrics.go @@ -5,11 +5,10 @@ import ( "regexp" "strings" + "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/alias" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/ptp4lconf" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/stats" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/types" - "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/utils" - "github.com/redhat-cne/sdk-go/pkg/event/ptp" log "github.com/sirupsen/logrus" ) @@ -176,18 +175,18 @@ func (p *PTPEventManager) ExtractMetrics(msg string) { case MasterClockType: ptpInterface, _ = ptp4lCfg.ByRole(types.SLAVE) if ptpInterface.Name != "" { - alias := utils.GetAlias(ptpInterface.Name) - ptpStats[master].SetAlias(alias) - UpdatePTPMetrics(master, processName, alias, ptpOffset, maxPtpOffset, frequencyAdjustment, delay) + aliasValue := alias.GetAlias(ptpInterface.Name) + ptpStats[master].SetAlias(aliasValue) + UpdatePTPMetrics(master, processName, aliasValue, ptpOffset, maxPtpOffset, frequencyAdjustment, delay) } else { // this should not happen log.Errorf("metrics found for empty interface %s", output) } default: if processName == ts2phcProcessName { - alias := utils.GetAlias(interfaceName) - ptpStats[master].SetAlias(alias) - UpdatePTPMetrics(master, processName, alias, ptpOffset, maxPtpOffset, frequencyAdjustment, delay) + aliasValue := alias.GetAlias(interfaceName) + ptpStats[master].SetAlias(aliasValue) + UpdatePTPMetrics(master, processName, aliasValue, ptpOffset, maxPtpOffset, frequencyAdjustment, delay) } } } else if strings.Contains(output, "nmea_status") && @@ -196,9 +195,9 @@ func (p *PTPEventManager) ExtractMetrics(msg string) { interfaceName, status, _, _ := extractNmeaMetrics(processName, output) // ts2phc return actual interface name unlike ptp4l ptpInterface = ptp4lconf.PTPInterface{Name: interfaceName} - alias := utils.GetAlias(interfaceName) + aliasValue := alias.GetAlias(interfaceName) // no event for nmeas status , change in GM will manage ptp events and sync states - UpdateNmeaStatusMetrics(processName, alias, status) + UpdateNmeaStatusMetrics(processName, aliasValue, status) } else if strings.Contains(output, "process_status") && processName == ts2phcProcessName { // do nothing processDown identifier will update metrics and stats @@ -287,33 +286,33 @@ func (p *PTPEventManager) ExtractMetrics(msg string) { case MasterClockType: // this ptp4l[5196819.100]: [ptp4l.0.config] master offset -2162130 s2 freq +22451884 path delay // Report events for master by masking the index number of the slave interface if ptpInterface.Name != "" { - alias := ptpStats[types.IFace(interfaceName)].Alias() - if alias == "" { - alias = utils.GetAlias(ptpInterface.Name) - ptpStats[types.IFace(interfaceName)].SetAlias(alias) + aliasValue := ptpStats[types.IFace(interfaceName)].Alias() + if aliasValue == "" { + aliasValue = alias.GetAlias(ptpInterface.Name) + ptpStats[types.IFace(interfaceName)].SetAlias(aliasValue) } // forT-BC only update metrics/ but we are missing maxAbs for T-BC, fro now it will use T-BC offsets - UpdatePTPMetrics(offsetSource, processName, alias, ptpOffset, float64(ptpStats[types.IFace(interfaceName)].MaxAbs()), + UpdatePTPMetrics(offsetSource, processName, aliasValue, ptpOffset, float64(ptpStats[types.IFace(interfaceName)].MaxAbs()), frequencyAdjustment, delay) // TBC does not trigger event for master offset // For TBC, ptp4l clock_state comes directly from log (s0/s2), never HOLDOVER if ptp4lCfg.ProfileType != ptp4lconf.TBC { - masterResource := fmt.Sprintf("%s/%s", alias, MasterClockType) + masterResource := fmt.Sprintf("%s/%s", aliasValue, MasterClockType) p.GenPTPEvent(profileName, ptpStats[types.IFace(interfaceName)], masterResource, int64(ptpOffset), syncState, ptp.PtpStateChange) - UpdateSyncStateMetrics(processName, alias, ptpStats[types.IFace(interfaceName)].LastSyncState()) + UpdateSyncStateMetrics(processName, aliasValue, ptpStats[types.IFace(interfaceName)].LastSyncState()) } else { // For TBC: store and use current syncState from log (s0/s2 only, no HOLDOVER) ptpStats[types.IFace(interfaceName)].SetLastSyncState(syncState) - UpdateSyncStateMetrics(processName, alias, syncState) + UpdateSyncStateMetrics(processName, aliasValue, syncState) } ptpStats[types.IFace(interfaceName)].AddValue(int64(ptpOffset)) } default: // for ts2phc the master stats are not updated at all, so rely on interface if processName == ts2phcProcessName { - alias := ptpStats[types.IFace(interfaceName)].Alias() - if alias == "" { - alias = utils.GetAlias(ptpInterface.Name) - ptpStats[types.IFace(interfaceName)].SetAlias(alias) + aliasValue := ptpStats[types.IFace(interfaceName)].Alias() + if aliasValue == "" { + aliasValue = alias.GetAlias(ptpInterface.Name) + ptpStats[types.IFace(interfaceName)].SetAlias(aliasValue) } // update ts2phc sync state to GM state if available,since GM State identifies PTP state // This identifies sync state of GM and adds ts2phc offset to verify if it has to stay in GM state or set new state @@ -321,7 +320,7 @@ func (p *PTPEventManager) ExtractMetrics(msg string) { // let the check happen again : GM state published by linuxptp-daemon already have checked ts2phc offset // TO GM State we need to know GM interface ; here MASTER stats will hold data of GM // and GM state will be held as dependant of master key - masterResource := fmt.Sprintf("%s/%s", alias, MasterClockType) + masterResource := fmt.Sprintf("%s/%s", aliasValue, MasterClockType) // use gm state to identify syncState // master will hold multiple ts2phc state as one state based on GM state // HANDLE case where there is no GM status but only ts2phc @@ -336,8 +335,8 @@ func (p *PTPEventManager) ExtractMetrics(msg string) { ptpStats[types.IFace(interfaceName)].SetLastOffset(int64(ptpOffset)) ptpStats[types.IFace(interfaceName)].AddValue(int64(ptpOffset)) } - UpdateSyncStateMetrics(processName, alias, ptpStats[types.IFace(interfaceName)].LastSyncState()) - UpdatePTPMetrics(offsetSource, processName, alias, ptpOffset, float64(ptpStats[types.IFace(interfaceName)].MaxAbs()), + UpdateSyncStateMetrics(processName, aliasValue, ptpStats[types.IFace(interfaceName)].LastSyncState()) + UpdatePTPMetrics(offsetSource, processName, aliasValue, ptpOffset, float64(ptpStats[types.IFace(interfaceName)].MaxAbs()), frequencyAdjustment, delay) } } @@ -362,13 +361,13 @@ func (p *PTPEventManager) processDownEvent(profileName, processName string, ptpS if iface != ClockRealTime && iface != master { ptpStats[iface].SetLastOffset(FreeRunOffsetValue) ptpStats[iface].SetLastSyncState(ptp.FREERUN) - alias := ptpStats[iface].Alias() - if alias == "" { - alias = utils.GetAlias(string(iface)) + aliasValue := ptpStats[iface].Alias() + if aliasValue == "" { + aliasValue = alias.GetAlias(string(iface)) } // update all ts2phc reported metrics as FREERUN - UpdateSyncStateMetrics(processName, alias, ptpStats[iface].LastSyncState()) - UpdatePTPMetrics(master, processName, alias, FreeRunOffsetValue, float64(ptpStats[iface].MaxAbs()), + UpdateSyncStateMetrics(processName, aliasValue, ptpStats[iface].LastSyncState()) + UpdatePTPMetrics(master, processName, aliasValue, FreeRunOffsetValue, float64(ptpStats[iface].MaxAbs()), float64(ptpStats[iface].FrequencyAdjustment()), float64(ptpStats[iface].Delay())) } } diff --git a/plugins/ptp_operator/ptp4lconf/ptp4lConfig.go b/plugins/ptp_operator/ptp4lconf/ptp4lConfig.go index af790b09..d130835b 100644 --- a/plugins/ptp_operator/ptp4lconf/ptp4lConfig.go +++ b/plugins/ptp_operator/ptp4lconf/ptp4lConfig.go @@ -23,8 +23,8 @@ import ( "strings" "github.com/fsnotify/fsnotify" + "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/alias" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/types" - "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/utils" log "github.com/sirupsen/logrus" ) @@ -87,6 +87,10 @@ func (p *PtpConfigUpdate) GetAllInterface() []*string { } } } + alias.Debug(func(s string, a ...any) { + log.Infof("GetAllInterface: "+s, a...) + }) + return interfaces } @@ -163,14 +167,14 @@ func (ptp4lCfg *PTP4lConfig) ByRole(role types.PtpPortRole) (PTPInterface, error // GetUnknownAlias ... when master port details are not know, get first interface alias name func (ptp4lCfg *PTP4lConfig) GetUnknownAlias() (string, error) { for _, p := range ptp4lCfg.Interfaces { - return utils.GetAlias(p.Name), nil + return alias.GetAlias(p.Name), nil } return "unknown", fmt.Errorf("interfaces not found for profilfe %s", ptp4lCfg.Profile) } // GetAliasByInterface ... get alias name by interface name func (ptp4lCfg *PTP4lConfig) GetAliasByInterface(p PTPInterface) string { - return utils.GetAlias(p.Name) + return alias.GetAlias(p.Name) } // UpdateRole ... update role diff --git a/plugins/ptp_operator/ptp_operator_plugin.go b/plugins/ptp_operator/ptp_operator_plugin.go index df781cd4..5e4feee1 100644 --- a/plugins/ptp_operator/ptp_operator_plugin.go +++ b/plugins/ptp_operator/ptp_operator_plugin.go @@ -388,6 +388,10 @@ func processPtp4lConfigFileUpdates() { log.Infof("updating ptp config changes for %s", *ptpConfigEvent.Name) switch ptpConfigEvent.Removed { case false: // create or modified + // Sync aliases when profile is loaded + if err := ptpMetrics.SyncAliasesFromDaemon(); err != nil { + log.Warnf("failed to sync aliases from linuxptp-daemon: %v", err) + } // get config fileName ptpConfigFileName := ptpTypes.ConfigName(*ptpConfigEvent.Name) // read all interface names from the config @@ -589,6 +593,7 @@ func processPtp4lConfigFileUpdates() { ptpMetrics.DeletedPTPMetrics(s.OffsetSource(), phc2sysProcessName, ClockRealTime) eventManager.PublishEvent(ptp.FREERUN, ptpMetrics.FreeRunOffsetValue, ClockRealTime, ptp.OsClockSyncStateChange) } + // TODO remove all metric CHECK THIS if s, found := ptpStats[MasterClockType]; found { if s.ProcessName() == ptp4lProcessName { ptpMetrics.DeletedPTPMetrics(s.OffsetSource(), ptp4lProcessName, s.Alias()) diff --git a/plugins/ptp_operator/utils/utils.go b/plugins/ptp_operator/utils/utils.go deleted file mode 100644 index 1533f707..00000000 --- a/plugins/ptp_operator/utils/utils.go +++ /dev/null @@ -1,50 +0,0 @@ -package utils - -import ( - "regexp" -) - -// GetAlias generates a PHC (PTP Hardware Clock) identifier alias from network interface names. -// It supports Intel and Mellanox naming formats with optional VLAN tags. -// -// Supported formats: -// - Intel: eth0 -> ethx, ens1f0 -> ens1fx, ens1f0.100 -> ens1fx.100 -// - Mellanox: enP2s2f0np0 -> enP2s2fx, enP2s2f0np0.100 -> enP2s2fx.100 -// -// For unsupported formats, returns the original interface name and logs an error. -// -// Parameters: -// - ifname: Network interface name (e.g., "ens1f0", "enP2s2f0np0", "eth0.100") -// -// Returns: -// - Alias string for PHC identification, or original name if format is unsupported -func GetAlias(ifname string) string { - alias := "" - if ifname != "" { - // Check if it's already an aliased interface (ends with 'x' before optional VLAN) - alreadyAliasedPattern := regexp.MustCompile(`^(.+?)x(\..+)?$`) - if alreadyAliasedPattern.MatchString(ifname) { - return ifname - } - - // Single regex to handle both Intel and Mellanox formats with optional VLAN - // Intel format: ens1f0, eth0, ens1f0.100 -> ens1fx, ethx, ens1fx.100 - // Mellanox format: enP2s2f0np0, enP2s2f0np0.100 -> enP2s2fx, enP2s2fx.100 - pattern := regexp.MustCompile(`^(.+?)(\d+)(?:np\d+)?(\..+)?$`) - matches := pattern.FindStringSubmatch(ifname) - - if len(matches) >= 3 { - // matches[1] contains the prefix (everything before the last digit sequence) - // matches[2] contains the digit sequence to replace - // matches[3] contains the VLAN part (including the dot) or empty string - alias = matches[1] + "x" - if len(matches) > 3 && matches[3] != "" { - alias += matches[3] // append VLAN part if present - } - } else { - // Interface doesn't match Intel or Mellanox format, return original interface name - alias = ifname - } - } - return alias -} diff --git a/plugins/ptp_operator/utils/utils_test.go b/plugins/ptp_operator/utils/utils_test.go deleted file mode 100644 index c052b9cc..00000000 --- a/plugins/ptp_operator/utils/utils_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package utils_test - -import ( - "fmt" - "testing" - - "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/utils" - "github.com/stretchr/testify/assert" -) - -type testCase struct { - ifname string - expectedAlias string -} - -func Test_GetAlias(t *testing.T) { - testCases := []testCase{ - {"eth0", "ethx"}, - {"eth1.100", "ethx.100"}, - {"eth1.100.XYZ", "ethx.100.XYZ"}, - // Mellanox style naming - {"enP2s2f0np0", "enP2s2fx"}, - {"enP1s1f1np1", "enP1s1fx"}, - {"enP10s5f3np2", "enP10s5fx"}, - {"ens1f3np3", "ens1fx"}, - // Mellanox style naming with VLAN - {"enP2s2f0np0.100", "enP2s2fx.100"}, - {"enP1s1f1np1.200", "enP1s1fx.200"}, - {"enP10s5f3np2.300.XYZ", "enP10s5fx.300.XYZ"}, - // Already aliased interfaces (should return as-is) - {"ens7fx", "ens7fx"}, - {"ethx", "ethx"}, - {"enP2s2fx", "enP2s2fx"}, - {"ens1fx.100", "ens1fx.100"}, - {"ens20f20.100", "ens20fx.100"}, - {"enP10s5fx.300.XYZ", "enP10s5fx.300.XYZ"}, - // Special master interface - {"master", "master"}, - // Fallback cases (interfaces that don't match Intel or Mellanox format) - {"wlan", "wlan"}, - {"lo", "lo"}, - {"virbr", "virbr"}, - {"docker", "docker"}, - } - for _, tc := range testCases { - t.Run(fmt.Sprintf("%s->%s", tc.ifname, tc.expectedAlias), func(t *testing.T) { - assert.Equal(t, tc.expectedAlias, utils.GetAlias(tc.ifname)) - }) - } -} From 15728d23117447a2a83e51a5d429e1609e316773 Mon Sep 17 00:00:00 2001 From: nocturnalastro Date: Tue, 24 Feb 2026 12:53:31 +0000 Subject: [PATCH 3/3] Update unit tests to handle new aliasing method --- plugins/ptp_operator/metrics/metrics_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/ptp_operator/metrics/metrics_test.go b/plugins/ptp_operator/metrics/metrics_test.go index e8f2590f..4b2d3b1b 100644 --- a/plugins/ptp_operator/metrics/metrics_test.go +++ b/plugins/ptp_operator/metrics/metrics_test.go @@ -21,6 +21,7 @@ import ( "github.com/prometheus/client_golang/prometheus/testutil" "github.com/redhat-cne/cloud-event-proxy/pkg/common" + "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/alias" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/config" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/metrics" "github.com/redhat-cne/cloud-event-proxy/plugins/ptp_operator/ptp4lconf" @@ -437,6 +438,12 @@ var testCases = []TestCase{ } func setup() { + alias.SetAlias("ens2f0", "ens2fx") + alias.SetAlias("ens2f1", "ens2fx") + alias.SetAlias("ens7f0", "ens7fx") + alias.SetAlias("ens3f0", "ens3fx") + alias.SetAlias("ens3f1", "ens3fx") + mockFS := &metrics.MockFileSystem{} scConfig = &common.SCConfiguration{StorePath: "/tmp/store"} metrics.Filesystem = mockFS