Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion addons/intel/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"os"
"slices"

"github.com/k8snetworkplumbingwg/linuxptp-daemon/pkg/leap"
"github.com/k8snetworkplumbingwg/linuxptp-daemon/pkg/ublox"
ptpv1 "github.com/k8snetworkplumbingwg/ptp-operator/api/v1"
)

Expand Down Expand Up @@ -55,7 +57,8 @@ func (opts *PluginOpts) allDevices() []string {

// GnssOptions defines GNSS-specific options common to Intel NIC plugins
type GnssOptions struct {
Disabled bool `json:"disabled"`
Disabled bool `json:"disabled"`
LeapSources LeapSourceOptions `json:"leapSources"`
}

// FileSystemInterface defines the interface for filesystem operations to enable mocking
Expand Down Expand Up @@ -91,3 +94,52 @@ func (fs *RealFileSystem) ReadLink(filename string) (string, error) {

// Default filesystem implementation
var filesystem FileSystemInterface = &RealFileSystem{}

// LeapSourceOptions defines enabled or disabled leap second sources
type LeapSourceOptions struct {
GPS bool `json:"gps"`
GLONASS bool `json:"glonass"`
BeiDou bool `json:"beidou"`
Galileo bool `json:"galileo"`
SBAS bool `json:"sbas"`
NavIC bool `json:"navic"`
}

// AllowedLeapSources converts the boolean flags into a map of
// ublox leap source IDs suitable for leap.SetAllowedLeapSources.
func (o LeapSourceOptions) AllowedLeapSources() map[uint8]bool {
mappings := []struct {
enabled bool
id uint8
}{
{o.GPS, ublox.LeapSourceGPS},
{o.GLONASS, ublox.LeapSourceGLONASS},
{o.BeiDou, ublox.LeapSourceBeiDou},
{o.Galileo, ublox.LeapSourceGalileo},
{o.SBAS, ublox.LeapSourceSBAS},
{o.NavIC, ublox.LeapSourceNavIC},
}

sources := make(map[uint8]bool)
for _, m := range mappings {
if m.enabled {
sources[m.id] = true
}
}
return sources
}

// defaultLeapSourceOptions returns LeapSourceOptions with all sources enabled.
func defaultLeapSourceOptions() LeapSourceOptions {
return LeapSourceOptions{
GPS: true, GLONASS: true, BeiDou: true,
Galileo: true, SBAS: true, NavIC: true,
}
}

// updateLeapManagerSources configures the LeapManager with the given leap source options.
func updateLeapManagerSources(sources LeapSourceOptions) {
if leap.LeapMgr != nil {
leap.LeapMgr.SetAllowedLeapSources(sources.AllowedLeapSources())
}
}
4 changes: 4 additions & 0 deletions addons/intel/e810.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type E810Opts struct {
EnableDefaultConfig bool `json:"enableDefaultConfig"`
UblxCmds UblxCmdList `json:"ublxCmds"`
PhaseInputs []PhaseInputs `json:"interconnections"`
Gnss GnssOptions `json:"gnss"`
}

// GetPhaseInputs implements PhaseInputsProvider
Expand Down Expand Up @@ -47,6 +48,7 @@ func OnPTPConfigChangeE810(data *interface{}, nodeProfile *ptpv1.PtpProfile) err
checkPinIndex(nodeProfile)

var e810Opts E810Opts
e810Opts.Gnss.LeapSources = defaultLeapSourceOptions()
var err error

e810Opts.EnableDefaultConfig = false
Expand Down Expand Up @@ -163,6 +165,8 @@ func OnPTPConfigChangeE810(data *interface{}, nodeProfile *ptpv1.PtpProfile) err
glog.Errorf("e810 failed to set Pin configuration for %s: %s", device, err)
}
}

updateLeapManagerSources(e810Opts.Gnss.LeapSources)
}
}
return nil
Expand Down
3 changes: 3 additions & 0 deletions addons/intel/e825.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func OnPTPConfigChangeE825(data *interface{}, nodeProfile *ptpv1.PtpProfile) err
pluginData := (*data).(*E825PluginData)
glog.Infof("calling onPTPConfigChange for e825 plugin (%s)", *nodeProfile.Name)
var e825Opts E825Opts
e825Opts.Gnss.LeapSources = defaultLeapSourceOptions()
var err error
var optsByteArray []byte

Expand Down Expand Up @@ -138,6 +139,8 @@ func OnPTPConfigChangeE825(data *interface{}, nodeProfile *ptpv1.PtpProfile) err
// Always enforce GNSS setting (default = enabled)
pluginData.setupGnss(e825Opts.Gnss)

updateLeapManagerSources(e825Opts.Gnss.LeapSources)

// BC sanity check and pin setup
if tbcConfigured(nodeProfile) {
if _, ok := nodeProfile.PtpSettings["upstreamPort"]; !ok {
Expand Down
36 changes: 22 additions & 14 deletions pkg/leap/leap-file.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const (
gpsToTaiDiff = 19
curreLsValidMask = 0x1
timeToLsEventValidMask = 0x2
leapSourceGps = 2
leapConfigMapName = "leap-configmap"
MaintenancePeriod = time.Minute * 1
pmcWindowStartHours = 12
Expand All @@ -54,10 +53,11 @@ type LeapManager struct {
leapFilePath string
leapFileName string
// UTC offset and its validity time
utcOffset int
utcOffsetTime time.Time
ptp4lConfigPath string
pmcLeapSent bool
utcOffset int
utcOffsetTime time.Time
ptp4lConfigPath string
pmcLeapSent bool
allowedLeapSources map[uint8]bool
}

type LeapEvent struct {
Expand All @@ -82,13 +82,14 @@ func New(kubeclient kubernetes.Interface, namespace string) (*LeapManager, error
defer lock.Unlock()
if LeapMgr == nil {
lm := &LeapManager{
UbloxLsInd: make(chan ublox.TimeLs, 2),
Close: make(chan bool),
client: kubeclient,
namespace: namespace,
leapFile: LeapFile{},
leapFilePath: defaultLeapFilePath,
leapFileName: defaultLeapFileName,
UbloxLsInd: make(chan ublox.TimeLs, 2),
Close: make(chan bool),
client: kubeclient,
namespace: namespace,
leapFile: LeapFile{},
leapFilePath: defaultLeapFilePath,
leapFileName: defaultLeapFileName,
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true},
}
err := lm.populateLeapData()
if err != nil {
Expand Down Expand Up @@ -163,6 +164,13 @@ func (l *LeapManager) SetPtp4lConfigPath(path string) {
l.ptp4lConfigPath = path
}

// SetAllowedLeapSources configures which GNSS leap second sources
// are accepted by processLeapIndication. Keys are ublox.LeapSourceXxx constants.
func (l *LeapManager) SetAllowedLeapSources(sources map[uint8]bool) {
glog.Infof("set Leap manager allowed leap sources to %v", sources)
l.allowedLeapSources = sources
}

func (l *LeapManager) renderLeapData() (*bytes.Buffer, error) {
templateStr := `# Do not edit
# This file is generated automatically by linuxptp-daemon
Expand Down Expand Up @@ -375,8 +383,8 @@ type leapIndResult struct {
func (l *LeapManager) processLeapIndication(data *ublox.TimeLs) (*leapIndResult, error) {

glog.Infof("Leap indication: %+v", data)
if data.SrcOfCurrLs != leapSourceGps {
glog.Info("Discarding Leap event not originating from GPS")
if !l.allowedLeapSources[data.SrcOfCurrLs] {
glog.Infof("Discarding Leap event from source %d (allowed: %v)", data.SrcOfCurrLs, l.allowedLeapSources)
return nil, nil
}
result := &leapIndResult{}
Expand Down
104 changes: 87 additions & 17 deletions pkg/leap/leap-file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ func Test_RenderLeapFile(t *testing.T) {
func Test_processLeapIndication_FutureLeapZero(t *testing.T) {
leapData := readTestData(t)
lm := &LeapManager{
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true},
}

ind := ublox.TimeLs{
Expand All @@ -90,9 +91,10 @@ func Test_processLeapIndication_FutureLeapZero(t *testing.T) {
func Test_processLeapIndication_FutureLeapNotZero(t *testing.T) {
leapData := readTestData(t)
lm := &LeapManager{
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true},
}

ind := ublox.TimeLs{
Expand All @@ -119,9 +121,10 @@ func Test_processLeapIndication_FutureLeapNotZero(t *testing.T) {
func Test_processLeapIndication_MissedLeapZero(t *testing.T) {
leapData := readTestData(t)
lm := &LeapManager{
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true},
}

ind := ublox.TimeLs{
Expand All @@ -145,9 +148,10 @@ func Test_processLeapIndication_MissedLeapZero(t *testing.T) {
func Test_processLeapIndication_MissedLeapNotZero(t *testing.T) {
leapData := readTestData(t)
lm := &LeapManager{
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true},
}

ind := ublox.TimeLs{
Expand All @@ -171,6 +175,71 @@ func Test_processLeapIndication_MissedLeapNotZero(t *testing.T) {
fmt.Println(res.leapTime)
}

func Test_processLeapIndication_BeiDouAllowed(t *testing.T) {
leapData := readTestData(t)
lm := &LeapManager{
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true, ublox.LeapSourceBeiDou: true},
}

ind := ublox.TimeLs{
SrcOfCurrLs: ublox.LeapSourceBeiDou,
CurrLs: 18,
SrcOfLsChange: ublox.LeapSourceBeiDou,
LsChange: 1,
TimeToLsEvent: 74329702,
DateOfLsGpsWn: 2441,
DateOfLsGpsDn: 7,
Valid: 3,
}
res, err := lm.processLeapIndication(&ind)
assert.NoError(t, err)
assert.NotNil(t, res)
assert.Equal(t, int(ind.CurrLs+ind.LsChange+19), res.leapSec)
}

func Test_processLeapIndication_SourceRejected(t *testing.T) {
leapData := readTestData(t)
lm := &LeapManager{
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
leapFile: *leapData,
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true},
}

ind := ublox.TimeLs{
SrcOfCurrLs: ublox.LeapSourceBeiDou,
CurrLs: 18,
SrcOfLsChange: ublox.LeapSourceBeiDou,
LsChange: 1,
TimeToLsEvent: 74329702,
DateOfLsGpsWn: 2441,
DateOfLsGpsDn: 7,
Valid: 3,
}
res, err := lm.processLeapIndication(&ind)
assert.NoError(t, err)
assert.Nil(t, res)
}

func Test_SetAllowedLeapSources(t *testing.T) {
lm := &LeapManager{
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true},
}
newSources := map[uint8]bool{
ublox.LeapSourceGPS: true,
ublox.LeapSourceBeiDou: true,
ublox.LeapSourceNavIC: true,
}
lm.SetAllowedLeapSources(newSources)
assert.True(t, lm.allowedLeapSources[ublox.LeapSourceGPS])
assert.True(t, lm.allowedLeapSources[ublox.LeapSourceBeiDou])
assert.True(t, lm.allowedLeapSources[ublox.LeapSourceNavIC])
assert.False(t, lm.allowedLeapSources[ublox.LeapSourceGLONASS])
}

func Test_populateLeapDataCmGood(t *testing.T) {
cm := &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{Namespace: "openshift-ptp", Name: "leap-configmap"},
Expand Down Expand Up @@ -281,11 +350,12 @@ func Test_handleLeapIndication(t *testing.T) {
os.Setenv("NODE_NAME", "test-node-name")
client := fake.NewSimpleClientset(cm)
lm := &LeapManager{
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
client: client,
namespace: "openshift-ptp",
retryUpdate: false,
UbloxLsInd: make(chan ublox.TimeLs),
Close: make(chan bool),
client: client,
namespace: "openshift-ptp",
retryUpdate: false,
allowedLeapSources: map[uint8]bool{ublox.LeapSourceGPS: true},
}
err := lm.populateLeapData()
assert.NoError(t, err)
Expand Down
10 changes: 10 additions & 0 deletions pkg/ublox/ublox.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,16 @@ func ExtractNavStatus(output string) int64 {
return -1
}

// UBX-NAV-TIMELS SrcOfCurrLs / SrcOfLsChange source identifiers
const (
LeapSourceGPS uint8 = 2
LeapSourceSBAS uint8 = 3
LeapSourceBeiDou uint8 = 4
LeapSourceGalileo uint8 = 5
LeapSourceGLONASS uint8 = 6
LeapSourceNavIC uint8 = 7
)

type TimeLs struct {
//Information source for the current number
// of leap seconds
Expand Down