Skip to content

Commit

Permalink
Update GM ClockQuality based on events
Browse files Browse the repository at this point in the history
Signed-off-by: Jack Ding <[email protected]>
  • Loading branch information
jzding authored and josephdrichard committed Jun 10, 2024
1 parent 61585e9 commit 8d54898
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 23 deletions.
2 changes: 1 addition & 1 deletion pkg/daemon/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ func processStatus(processName, messageTag string, status int64) {
}

func (p *ptpProcess) updateClockClass(c *net.Conn) {
if _, matches, e := pmc.RunPMCExp(p.configName, pmc.CmdParentDataSet, pmc.ClockClassChangeRegEx); e == nil {
if _, matches, e := pmc.RunPMCExp(p.configName, pmc.CmdGetParentDataSet, pmc.ClockClassChangeRegEx); e == nil {
//regex: 'gm.ClockClass[[:space:]]+(\d+)'
//match 1: 'gm.ClockClass 135'
//match 2: '135'
Expand Down
74 changes: 52 additions & 22 deletions pkg/daemon/pmc/pmc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,30 @@ package pmc

import (
"fmt"
"github.com/golang/glog"
"github.com/google/goexpect"
"regexp"
"strings"
"time"

"github.com/golang/glog"
expect "github.com/google/goexpect"
"github.com/openshift/k8snetworkplumbingwg/pkg/protocol"
)

var (
ClockClassChangeRegEx = regexp.MustCompile(`gm.ClockClass[[:space:]]+(\d+)`)
ClockClassUpdateRegEx = regexp.MustCompile(`clockClass[[:space:]]+(\d+)`)
CmdParentDataSet = "GET PARENT_DATA_SET"
CmdUpdateGMClass_LOCKED = `SET GRANDMASTER_SETTINGS_NP clockClass %d \
clockAccuracy 0x21 offsetScaledLogVariance 0x436a \
currentUtcOffset 37 leap61 0 leap59 0 currentUtcOffsetValid 1 \
ptpTimescale 1 timeTraceable 0 frequencyTraceable 0
timeSource 0xa0`
CmdUpdateGMClass_FREERUN = `SET GRANDMASTER_SETTINGS_NP clockClass %d \
clockAccuracy 0xFE offsetScaledLogVariance 0x436a \
currentUtcOffset 37 leap61 0 leap59 0 currentUtcOffsetValid 1 \
ptpTimescale 1 timeTraceable 0 frequencyTraceable 0
timeSource 0xa0`
cmdTimeout = 500 * time.Millisecond
ClockClassChangeRegEx = regexp.MustCompile(`gm.ClockClass[[:space:]]+(\d+)`)
ClockClassUpdateRegEx = regexp.MustCompile(`clockClass[[:space:]]+(\d+)`)
GetGMSettingsRegEx = regexp.MustCompile(`clockClass[[:space:]]+(\d+)[[:space:]]+clockAccuracy[[:space:]]+(0x\d+)`)
CmdGetParentDataSet = "GET PARENT_DATA_SET"
CmdGetGMSettings = "GET GRANDMASTER_SETTINGS_NP"
CmdSetGMSettings = "SET GRANDMASTER_SETTINGS_NP"
// GET GRANDMASTER_SETTINGS_NP sometimes takes more than 2 seconds
cmdTimeout = 5000 * time.Millisecond
)

// RunPMCExp ... go expect to run PMC util cmd
func RunPMCExp(configFileName, cmdStr string, promptRE *regexp.Regexp) (result string, matches []string, err error) {
glog.Infof("pmc read config from /var/run/%s", configFileName)
glog.Infof("pmc run command: %s", cmdStr)
e, _, err := expect.Spawn(fmt.Sprintf("pmc -u -b 1 -f /var/run/%s", configFileName), -1)
if err != nil {
return "", []string{}, err
Expand All @@ -38,24 +37,55 @@ func RunPMCExp(configFileName, cmdStr string, promptRE *regexp.Regexp) (result s
glog.Errorf("pmc result match error %s", err)
return
}
glog.Infof("pmc result: %s", result)
err = e.Send("\x03")
}
return
}

// RunUpdatePMCExp ... run pmc update command
func RunUpdatePMCExp(configFileName, cmdStr string, promptRE *regexp.Regexp) (result string, matches []string, err error) {
// RunPMCExpGetGMSettings ... get current GRANDMASTER_SETTINGS_NP
func RunPMCExpGetGMSettings(configFileName string) (g protocol.GrandmasterSettings, err error) {
cmdStr := CmdGetGMSettings
glog.Infof("pmc read config from /var/run/%s", configFileName)
glog.Infof("pmc run command: %s", cmdStr)
e, _, err := expect.Spawn(fmt.Sprintf("pmc -u -b 1 -f /var/run/%s", configFileName), -1)
if err != nil {
return "", []string{}, err
return g, err
}
defer e.Close()
if err = e.Send(cmdStr + "\n"); err == nil {
result, matches, err = e.Expect(promptRE, cmdTimeout)
result, matches, err := e.Expect(regexp.MustCompile(g.RegEx()), cmdTimeout)
if err != nil {
glog.Errorf("pmc result match error %s", err)
return
fmt.Printf("pmc result match error %s\n", err)
return g, err
}
glog.Infof("pmc result: %s", result)
for i, m := range matches[1:] {
g.Update(g.Keys()[i], m)
}
err = e.Send("\x03")
}
return
}

// RunPMCExpSetGMSettings ... set GRANDMASTER_SETTINGS_NP
func RunPMCExpSetGMSettings(configFileName string, g protocol.GrandmasterSettings) (err error) {
cmdStr := CmdSetGMSettings
cmdStr += strings.Replace(g.String(), "\n", " ", -1)
glog.Infof("pmc read config from /var/run/%s", configFileName)
glog.Infof("pmc run command: %s", cmdStr)
e, _, err := expect.Spawn(fmt.Sprintf("pmc -u -b 1 -f /var/run/%s", configFileName), -1)
if err != nil {
return err
}
defer e.Close()
if err = e.Send(cmdStr + "\n"); err == nil {
result, _, err := e.Expect(regexp.MustCompile(g.RegEx()), cmdTimeout)
if err != nil {
fmt.Printf("pmc result match error %s\n", err)
return err
}
glog.Infof("pmc result: %s", result)
err = e.Send("\x03")
}
return
Expand Down
153 changes: 153 additions & 0 deletions pkg/protocol/type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package protocol

import (
"fmt"
"strconv"
"strings"

"github.com/facebook/time/ptp/protocol"
)

// extend fbprotocol.ClockClass according to https://www.itu.int/rec/T-REC-G.8275.1-202211-I/en section 6.4 table 3
const (
ClockClassFreerun protocol.ClockClass = 248
)

type GrandmasterSettings struct {
ClockQuality protocol.ClockQuality
TimePropertiesDS TimePropertiesDS
}

type TimePropertiesDS struct {
CurrentUtcOffset int32
CurrentUtcOffsetValid bool
Leap59 bool
Leap61 bool
TimeTraceable bool
FrequencyTraceable bool
PtpTimescale bool
TimeSource protocol.TimeSource
}

func (g *GrandmasterSettings) String() string {
if g == nil {
return ""

}
result := fmt.Sprintf(" clockClass %d\n", g.ClockQuality.ClockClass)
result += fmt.Sprintf(" clockAccuracy 0x%x\n", g.ClockQuality.ClockAccuracy)
result += fmt.Sprintf(" offsetScaledLogVariance 0x%x\n", g.ClockQuality.OffsetScaledLogVariance)
result += fmt.Sprintf(" currentUtcOffset %d\n", g.TimePropertiesDS.CurrentUtcOffset)
result += fmt.Sprintf(" leap61 %d\n", btoi(g.TimePropertiesDS.Leap61))
result += fmt.Sprintf(" leap59 %d\n", btoi(g.TimePropertiesDS.Leap59))
result += fmt.Sprintf(" currentUtcOffsetValid %d\n", btoi(g.TimePropertiesDS.CurrentUtcOffsetValid))
result += fmt.Sprintf(" ptpTimescale %d\n", btoi(g.TimePropertiesDS.PtpTimescale))
result += fmt.Sprintf(" timeTraceable %d\n", btoi(g.TimePropertiesDS.TimeTraceable))
result += fmt.Sprintf(" frequencyTraceable %d\n", btoi(g.TimePropertiesDS.FrequencyTraceable))
result += fmt.Sprintf(" timeSource 0x%x\n", uint(g.TimePropertiesDS.TimeSource))
return result
}

// Keys returns variables names in order of pmc command results
func (g *GrandmasterSettings) Keys() []string {
return []string{"clockClass", "clockAccuracy", "offsetScaledLogVariance",
"currentUtcOffset", "leap61", "leap59", "currentUtcOffsetValid",
"ptpTimescale", "timeTraceable", "frequencyTraceable", "timeSource"}
}

func (g *GrandmasterSettings) ValueRegEx() map[string]string {
return map[string]string{
"clockClass": `(\d+)`,
"clockAccuracy": `(0x[\da-f]+)`,
"offsetScaledLogVariance": `(0x[\da-f]+)`,
"currentUtcOffset": `(\d+)`,
"currentUtcOffsetValid": `([01])`,
"leap59": `([01])`,
"leap61": `([01])`,
"timeTraceable": `([01])`,
"frequencyTraceable": `([01])`,
"ptpTimescale": `([01])`,
"timeSource": `(0x[\da-f]+)`,
}
}

func (g *GrandmasterSettings) RegEx() string {
result := ""
for _, k := range g.Keys() {
result += `[[:space:]]+` + k + `[[:space:]]+` + g.ValueRegEx()[k]
}
return result
}

func (g *GrandmasterSettings) Update(key string, value string) {
switch key {
case "clockClass":
g.ClockQuality.ClockClass = protocol.ClockClass(stou8(value))
case "clockAccuracy":
g.ClockQuality.ClockAccuracy = protocol.ClockAccuracy(stou8h(value))
case "offsetScaledLogVariance":
g.ClockQuality.OffsetScaledLogVariance = stou16h(value)
case "currentUtcOffset":
g.TimePropertiesDS.CurrentUtcOffset = stoi32(value)
case "currentUtcOffsetValid":
g.TimePropertiesDS.CurrentUtcOffsetValid = stob(value)
case "leap59":
g.TimePropertiesDS.Leap59 = stob(value)
case "leap61":
g.TimePropertiesDS.Leap61 = stob(value)
case "timeTraceable":
g.TimePropertiesDS.TimeTraceable = stob(value)
case "frequencyTraceable":
g.TimePropertiesDS.FrequencyTraceable = stob(value)
case "ptpTimescale":
g.TimePropertiesDS.PtpTimescale = stob(value)
case "timeSource":
g.TimePropertiesDS.TimeSource = protocol.TimeSource(stou8h(value))
}
}

func btoi(b bool) uint8 {
if b {
return 1
}
return 0
}

func stob(s string) bool {
if s == "1" {
return true
}
return false
}

func stou8(s string) uint8 {
uint64Value, err := strconv.ParseUint(s, 10, 8)
if err != nil {
fmt.Printf("%v\n", err)
}
return uint8(uint64Value)
}

func stou8h(s string) uint8 {
uint64Value, err := strconv.ParseUint(strings.Replace(s, "0x", "", 1), 16, 8)
if err != nil {
fmt.Printf("%v\n", err)
}
return uint8(uint64Value)
}

func stou16h(s string) uint16 {
uint64Value, err := strconv.ParseUint(strings.Replace(s, "0x", "", 1), 16, 16)
if err != nil {
fmt.Printf("%v\n", err)
}
return uint16(uint64Value)
}

func stoi32(s string) int32 {
int64Value, err := strconv.ParseInt(s, 10, 32)
if err != nil {
fmt.Printf("%v\n", err)
}
return int32(int64Value)
}

0 comments on commit 8d54898

Please sign in to comment.