From 15334aab4ad1b09cb698175adf5a02d7cb6fa410 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Wed, 3 Jul 2019 13:44:09 +0200 Subject: Fix error counters for VPP 19.04 Change-Id: I87251362668bbe9a31f52c1b5e9b3ab596f7b2f3 Signed-off-by: Ondrej Fabry --- adapter/socketclient/socketclient.go | 8 ++- adapter/stats_api.go | 10 +-- adapter/statsclient/stat_segment.go | 136 +++++++++++++++++++++++++++++++++-- adapter/statsclient/statsclient.go | 133 ++++------------------------------ adapter/vpp_api.go | 11 ++- core/log.go | 2 +- 6 files changed, 161 insertions(+), 139 deletions(-) diff --git a/adapter/socketclient/socketclient.go b/adapter/socketclient/socketclient.go index daca005..2e6d0af 100644 --- a/adapter/socketclient/socketclient.go +++ b/adapter/socketclient/socketclient.go @@ -36,8 +36,8 @@ import ( ) const ( - // DefaultSocketName is default VPP API socket file name - DefaultSocketName = "/run/vpp-api.sock" + // DefaultSocketName is default VPP API socket file path. + DefaultSocketName = adapter.DefaultBinapiSocket ) var ( @@ -58,7 +58,8 @@ var ( // DebugMsgIds is global variable that determines debug mode for msg ids DebugMsgIds = os.Getenv("DEBUG_GOVPP_SOCKMSG") != "" - Log = logger.New() // global logger + // Log is global logger + Log = logger.New() ) // init initializes global logger, which logs debug level messages to stdout. @@ -66,6 +67,7 @@ func init() { Log.Out = os.Stdout if Debug { Log.Level = logger.DebugLevel + Log.Debug("govpp/socketclient: enabled debug mode") } } diff --git a/adapter/stats_api.go b/adapter/stats_api.go index 798fcbd..90ecd78 100644 --- a/adapter/stats_api.go +++ b/adapter/stats_api.go @@ -19,14 +19,14 @@ import ( "fmt" ) -var ( - ErrStatDirBusy = errors.New("stat dir busy") - ErrStatDumpBusy = errors.New("stat dump busy") +const ( + // DefaultStatsSocket defines a default socket file path for VPP stats API. + DefaultStatsSocket = "/run/vpp/stats.sock" ) var ( - // DefaultStatsSocket is the default path for the VPP stat socket file. - DefaultStatsSocket = "/run/vpp/stats.sock" + ErrStatDirBusy = errors.New("stat dir busy") + ErrStatDumpBusy = errors.New("stat dump busy") ) // StatsAPI provides connection to VPP stats API. diff --git a/adapter/statsclient/stat_segment.go b/adapter/statsclient/stat_segment.go index 507a9ea..1875f17 100644 --- a/adapter/statsclient/stat_segment.go +++ b/adapter/statsclient/stat_segment.go @@ -31,6 +31,12 @@ var ( maxWaitInProgress = time.Second * 1 ) +type statDirectoryType int32 + +func (t statDirectoryType) String() string { + return adapter.StatType(t).String() +} + type statSegDirectoryEntry struct { directoryType statDirectoryType // unionData can represent: offset, index or value @@ -39,16 +45,12 @@ type statSegDirectoryEntry struct { name [128]byte } -type statDirectoryType int32 - -func (t statDirectoryType) String() string { - return adapter.StatType(t).String() -} - type statSegment struct { sharedHeader []byte memorySize int64 + // oldHeader defines version 0 for stat segment + // and is used for VPP 19.04 oldHeader bool } @@ -119,7 +121,7 @@ func (c *statSegment) connect(sockName string) error { // we try to provide fallback support by skipping it in header if header.version > MaxVersion && header.inProgress > 1 && header.epoch == 0 { h := c.readHeaderOld() - Log.Infof("statsclient: falling back to old stat segment version (VPP 19.04): %+v", h) + Log.Warnf("statsclient: falling back to old stat segment version (VPP 19.04): %+v", h) c.oldHeader = true } @@ -137,6 +139,126 @@ func (c *statSegment) disconnect() error { return nil } +func (c *statSegment) copyData(dirEntry *statSegDirectoryEntry) adapter.Stat { + switch typ := adapter.StatType(dirEntry.directoryType); typ { + case adapter.ScalarIndex: + return adapter.ScalarStat(dirEntry.unionData) + + case adapter.ErrorIndex: + _, errOffset, _ := c.readOffsets() + offsetVector := unsafe.Pointer(&c.sharedHeader[errOffset]) + + var errData adapter.Counter + if c.oldHeader { + // error were not vector (per-worker) in VPP 19.04 + offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(uint64(0)) + val := *(*adapter.Counter)(add(offsetVector, offset)) + errData = val + } else { + vecLen := vectorLen(offsetVector) + for i := uint64(0); i < vecLen; i++ { + cb := *(*uint64)(add(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0)))) + offset := uintptr(cb) + uintptr(dirEntry.unionData)*unsafe.Sizeof(adapter.Counter(0)) + val := *(*adapter.Counter)(add(unsafe.Pointer(&c.sharedHeader[0]), offset)) + errData += val + } + } + return adapter.ErrorStat(errData) + + case adapter.SimpleCounterVector: + if dirEntry.unionData == 0 { + Log.Debugf("\toffset is not valid") + break + } else if dirEntry.unionData >= uint64(len(c.sharedHeader)) { + Log.Debugf("\toffset out of range") + break + } + + simpleCounter := unsafe.Pointer(&c.sharedHeader[dirEntry.unionData]) // offset + vecLen := vectorLen(simpleCounter) + offsetVector := add(unsafe.Pointer(&c.sharedHeader[0]), uintptr(dirEntry.offsetVector)) + + data := make([][]adapter.Counter, vecLen) + for i := uint64(0); i < vecLen; i++ { + cb := *(*uint64)(add(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0)))) + counterVec := unsafe.Pointer(&c.sharedHeader[uintptr(cb)]) + vecLen2 := vectorLen(counterVec) + for j := uint64(0); j < vecLen2; j++ { + offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0)) + val := *(*adapter.Counter)(add(counterVec, offset)) + data[i] = append(data[i], val) + } + } + return adapter.SimpleCounterStat(data) + + case adapter.CombinedCounterVector: + if dirEntry.unionData == 0 { + Log.Debugf("\toffset is not valid") + break + } else if dirEntry.unionData >= uint64(len(c.sharedHeader)) { + Log.Debugf("\toffset out of range") + break + } + + combinedCounter := unsafe.Pointer(&c.sharedHeader[dirEntry.unionData]) // offset + vecLen := vectorLen(combinedCounter) + offsetVector := add(unsafe.Pointer(&c.sharedHeader[0]), uintptr(dirEntry.offsetVector)) + + data := make([][]adapter.CombinedCounter, vecLen) + for i := uint64(0); i < vecLen; i++ { + cb := *(*uint64)(add(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0)))) + counterVec := unsafe.Pointer(&c.sharedHeader[uintptr(cb)]) + vecLen2 := vectorLen(counterVec) + for j := uint64(0); j < vecLen2; j++ { + offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{}) + val := *(*adapter.CombinedCounter)(add(counterVec, offset)) + data[i] = append(data[i], val) + } + } + return adapter.CombinedCounterStat(data) + + case adapter.NameVector: + if dirEntry.unionData == 0 { + Log.Debugf("\toffset is not valid") + break + } else if dirEntry.unionData >= uint64(len(c.sharedHeader)) { + Log.Debugf("\toffset out of range") + break + } + + nameVector := unsafe.Pointer(&c.sharedHeader[dirEntry.unionData]) // offset + vecLen := vectorLen(nameVector) + offsetVector := add(unsafe.Pointer(&c.sharedHeader[0]), uintptr(dirEntry.offsetVector)) + + data := make([]adapter.Name, vecLen) + for i := uint64(0); i < vecLen; i++ { + cb := *(*uint64)(add(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0)))) + if cb == 0 { + Log.Debugf("\tname vector cb out of range") + continue + } + nameVec := unsafe.Pointer(&c.sharedHeader[cb]) + vecLen2 := vectorLen(nameVec) + + var nameStr []byte + for j := uint64(0); j < vecLen2; j++ { + offset := uintptr(j) * unsafe.Sizeof(byte(0)) + val := *(*byte)(add(nameVec, offset)) + if val > 0 { + nameStr = append(nameStr, val) + } + } + data[i] = adapter.Name(nameStr) + } + return adapter.NameStat(data) + + default: + Log.Warnf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name) + } + + return nil +} + type sharedHeaderBase struct { epoch int64 inProgress int64 diff --git a/adapter/statsclient/statsclient.go b/adapter/statsclient/statsclient.go index ecba292..f715a70 100644 --- a/adapter/statsclient/statsclient.go +++ b/adapter/statsclient/statsclient.go @@ -40,7 +40,7 @@ func init() { Log.Out = os.Stdout if Debug { Log.Level = logger.DebugLevel - Log.Debug("enabled debug mode") + Log.Debug("govpp/statsclient: enabled debug mode") } } @@ -62,12 +62,16 @@ func NewStatsClient(sockAddr string) *StatsClient { } } -const sockNotFoundWarn = `VPP stats socket not found at: %s! - Check if VPP is running with stats segment enabled. - To enable it include following section in VPP config: - statseg { - default - } +const sockNotFoundWarn = `stats socket not found at: %s +------------------------------------------------------------ + VPP stats socket is missing! + Is VPP running with stats segment enabled? + + To enable it add following section to startup config: + statseg { + default + } +------------------------------------------------------------ ` func (c *StatsClient) Connect() error { @@ -184,7 +188,7 @@ func (c *StatsClient) DumpStats(patterns ...string) (entries []*adapter.StatEntr Data: c.copyData(dirEntry), } - Log.Debugf("\tentry data: %#v", entry.Data) + Log.Debugf("\tentry data: %+v %#v (%T)", entry.Data, entry.Data, entry.Data) if nameMatches(entry.Name, patterns) { entries = append(entries, &entry) @@ -198,119 +202,6 @@ func (c *StatsClient) DumpStats(patterns ...string) (entries []*adapter.StatEntr return entries, nil } -func (c *StatsClient) copyData(dirEntry *statSegDirectoryEntry) adapter.Stat { - switch typ := adapter.StatType(dirEntry.directoryType); typ { - case adapter.ScalarIndex: - return adapter.ScalarStat(dirEntry.unionData) - - case adapter.ErrorIndex: - _, errOffset, _ := c.readOffsets() - offsetVector := unsafe.Pointer(&c.sharedHeader[errOffset]) - vecLen := vectorLen(offsetVector) - - var errData adapter.Counter - for i := uint64(0); i < vecLen; i++ { - cb := *(*uint64)(add(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0)))) - offset := uintptr(cb) + uintptr(dirEntry.unionData)*unsafe.Sizeof(adapter.Counter(0)) - val := *(*adapter.Counter)(add(unsafe.Pointer(&c.sharedHeader[0]), offset)) - errData += val - } - return adapter.ErrorStat(errData) - - case adapter.SimpleCounterVector: - if dirEntry.unionData == 0 { - Log.Debugf("\toffset is not valid") - break - } else if dirEntry.unionData >= uint64(len(c.sharedHeader)) { - Log.Debugf("\toffset out of range") - break - } - - simpleCounter := unsafe.Pointer(&c.sharedHeader[dirEntry.unionData]) // offset - vecLen := vectorLen(simpleCounter) - offsetVector := add(unsafe.Pointer(&c.sharedHeader[0]), uintptr(dirEntry.offsetVector)) - - data := make([][]adapter.Counter, vecLen) - for i := uint64(0); i < vecLen; i++ { - cb := *(*uint64)(add(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0)))) - counterVec := unsafe.Pointer(&c.sharedHeader[uintptr(cb)]) - vecLen2 := vectorLen(counterVec) - for j := uint64(0); j < vecLen2; j++ { - offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0)) - val := *(*adapter.Counter)(add(counterVec, offset)) - data[i] = append(data[i], val) - } - } - return adapter.SimpleCounterStat(data) - - case adapter.CombinedCounterVector: - if dirEntry.unionData == 0 { - Log.Debugf("\toffset is not valid") - break - } else if dirEntry.unionData >= uint64(len(c.sharedHeader)) { - Log.Debugf("\toffset out of range") - break - } - - combinedCounter := unsafe.Pointer(&c.sharedHeader[dirEntry.unionData]) // offset - vecLen := vectorLen(combinedCounter) - offsetVector := add(unsafe.Pointer(&c.sharedHeader[0]), uintptr(dirEntry.offsetVector)) - - data := make([][]adapter.CombinedCounter, vecLen) - for i := uint64(0); i < vecLen; i++ { - cb := *(*uint64)(add(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0)))) - counterVec := unsafe.Pointer(&c.sharedHeader[uintptr(cb)]) - vecLen2 := vectorLen(counterVec) - for j := uint64(0); j < vecLen2; j++ { - offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{}) - val := *(*adapter.CombinedCounter)(add(counterVec, offset)) - data[i] = append(data[i], val) - } - } - return adapter.CombinedCounterStat(data) - - case adapter.NameVector: - if dirEntry.unionData == 0 { - Log.Debugf("\toffset is not valid") - break - } else if dirEntry.unionData >= uint64(len(c.sharedHeader)) { - Log.Debugf("\toffset out of range") - break - } - - nameVector := unsafe.Pointer(&c.sharedHeader[dirEntry.unionData]) // offset - vecLen := vectorLen(nameVector) - offsetVector := add(unsafe.Pointer(&c.sharedHeader[0]), uintptr(dirEntry.offsetVector)) - - data := make([]adapter.Name, vecLen) - for i := uint64(0); i < vecLen; i++ { - cb := *(*uint64)(add(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0)))) - if cb == 0 { - Log.Debugf("\tname vector cb out of range") - continue - } - nameVec := unsafe.Pointer(&c.sharedHeader[cb]) - vecLen2 := vectorLen(nameVec) - - var nameStr []byte - for j := uint64(0); j < vecLen2; j++ { - offset := uintptr(j) * unsafe.Sizeof(byte(0)) - val := *(*byte)(add(nameVec, offset)) - if val > 0 { - nameStr = append(nameStr, val) - } - } - data[i] = adapter.Name(nameStr) - } - return adapter.NameStat(data) - - default: - Log.Warnf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name) - } - - return nil -} - func nameMatches(name string, patterns []string) bool { if len(patterns) == 0 { return true diff --git a/adapter/vpp_api.go b/adapter/vpp_api.go index 7d14633..2391420 100644 --- a/adapter/vpp_api.go +++ b/adapter/vpp_api.go @@ -18,8 +18,15 @@ import ( "errors" ) -// ErrNotImplemented is an error returned when missing implementation. -var ErrNotImplemented = errors.New("not implemented for this OS") +const ( + // DefaultBinapiSocket defines a default socket file path for VPP binary API. + DefaultBinapiSocket = "/run/vpp-api.sock" +) + +var ( + // ErrNotImplemented is an error returned when missing implementation. + ErrNotImplemented = errors.New("not implemented for this OS") +) // MsgCallback defines func signature for message callback. type MsgCallback func(msgID uint16, data []byte) diff --git a/core/log.go b/core/log.go index 035c159..5960d6b 100644 --- a/core/log.go +++ b/core/log.go @@ -18,7 +18,7 @@ func init() { log.Out = os.Stdout if debug { log.Level = logger.DebugLevel - log.Debugf("debug mode enabled") + log.Debugf("govpp/core: debug mode enabled") } } -- cgit 1.2.3-korg