1 // Copyright (c) 2020 Cisco and/or its affiliates.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
23 "git.fd.io/govpp.git/adapter"
26 type statSegmentV2 struct {
31 type sharedHeaderV2 struct {
36 dirVector unsafe.Pointer
37 errorVector unsafe.Pointer
40 type statSegDirectoryEntryV2 struct {
42 // unionData can represent:
51 func newStatSegmentV2(data []byte, size int64) *statSegmentV2 {
52 return &statSegmentV2{
58 func (ss *statSegmentV2) loadSharedHeader(b []byte) (header sharedHeaderV2) {
59 h := (*sharedHeaderV2)(unsafe.Pointer(&b[0]))
60 return sharedHeaderV2{
61 version: atomic.LoadUint64(&h.version),
62 base: atomic.LoadPointer(&h.base),
63 epoch: atomic.LoadInt64(&h.epoch),
64 inProgress: atomic.LoadInt64(&h.inProgress),
65 dirVector: atomic.LoadPointer(&h.dirVector),
66 errorVector: atomic.LoadPointer(&h.errorVector),
70 func (ss *statSegmentV2) GetDirectoryVector() dirVector {
71 header := ss.loadSharedHeader(ss.sharedHeader)
72 return ss.adjust(dirVector(&header.dirVector))
75 func (ss *statSegmentV2) GetStatDirOnIndex(v dirVector, index uint32) (dirSegment, dirName, dirType) {
76 statSegDir := dirSegment(uintptr(v) + uintptr(index)*unsafe.Sizeof(statSegDirectoryEntryV2{}))
77 dir := (*statSegDirectoryEntryV2)(statSegDir)
79 for n := 0; n < len(dir.name); n++ {
85 return statSegDir, name, dir.directoryType
88 func (ss *statSegmentV2) GetEpoch() (int64, bool) {
89 sh := ss.loadSharedHeader(ss.sharedHeader)
90 return sh.epoch, sh.inProgress != 0
93 func (ss *statSegmentV2) CopyEntryData(segment dirSegment, index uint32) adapter.Stat {
94 dirEntry := (*statSegDirectoryEntryV2)(segment)
95 if dirEntry.unionData == 0 {
96 debugf("data value or pointer not defined for %s", dirEntry.name)
100 switch adapter.StatType(dirEntry.directoryType) {
101 case statDirScalarIndex:
102 return adapter.ScalarStat(dirEntry.unionData)
104 case statDirErrorIndex:
105 dirVector := ss.getErrorVector()
106 if dirVector == nil {
107 debugf("error vector pointer is out of range for %s", dirEntry.name)
110 vecLen := *(*uint32)(vectorLen(dirVector))
111 var errData []adapter.Counter
112 for i := uint32(0); i < vecLen; i++ {
113 cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
114 cbVal := ss.adjust(vectorLen(cb))
116 debugf("error counter pointer out of range")
119 offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
120 val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
121 errData = append(errData, val)
123 return adapter.ErrorStat(errData)
125 case statDirCounterVectorSimple:
126 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
127 if dirVector == nil {
128 debugf("data vector pointer is out of range for %s", dirEntry.name)
131 vecLen := *(*uint32)(vectorLen(dirVector))
132 data := make([][]adapter.Counter, vecLen)
133 for i := uint32(0); i < vecLen; i++ {
134 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
135 counterVector := ss.adjust(vectorLen(counterVectorOffset))
136 if counterVector == nil {
137 debugf("counter (vector simple) pointer out of range")
140 counterVectorLength := *(*uint32)(vectorLen(counterVector))
141 if index == ^uint32(0) {
142 data[i] = make([]adapter.Counter, counterVectorLength)
143 for j := uint32(0); j < counterVectorLength; j++ {
144 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
145 data[i][j] = *(*adapter.Counter)(statSegPointer(counterVector, offset))
148 data[i] = make([]adapter.Counter, 1) // expect single value
149 for j := uint32(0); j < counterVectorLength; j++ {
150 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
152 data[i][0] = *(*adapter.Counter)(statSegPointer(counterVector, offset))
158 return adapter.SimpleCounterStat(data)
160 case statDirCounterVectorCombined:
161 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
162 if dirVector == nil {
163 debugf("data vector pointer is out of range for %s", dirEntry.name)
166 vecLen := *(*uint32)(vectorLen(dirVector))
167 data := make([][]adapter.CombinedCounter, vecLen)
168 for i := uint32(0); i < vecLen; i++ {
169 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
170 counterVector := ss.adjust(vectorLen(counterVectorOffset))
171 if counterVector == nil {
172 debugf("counter (vector combined) pointer out of range")
175 counterVectorLength := *(*uint32)(vectorLen(counterVector))
176 if index == ^uint32(0) {
177 data[i] = make([]adapter.CombinedCounter, counterVectorLength)
178 for j := uint32(0); j < counterVectorLength; j++ {
179 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
180 data[i][j] = *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
183 data[i] = make([]adapter.CombinedCounter, 1) // expect single value pair
184 for j := uint32(0); j < counterVectorLength; j++ {
185 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
187 data[i][0] = *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
193 return adapter.CombinedCounterStat(data)
195 case statDirNameVector:
196 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
197 if dirVector == nil {
198 debugf("data vector pointer is out of range for %s", dirEntry.name)
201 vecLen := *(*uint32)(vectorLen(dirVector))
202 data := make([]adapter.Name, vecLen)
203 for i := uint32(0); i < vecLen; i++ {
204 nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
205 if uintptr(nameVectorOffset) == 0 {
206 debugf("name vector out of range for %s (%v)", dirEntry.name, i)
209 nameVector := ss.adjust(vectorLen(nameVectorOffset))
210 if nameVector == nil {
211 debugf("name data pointer out of range")
214 nameVectorLen := *(*uint32)(vectorLen(nameVector))
215 name := make([]byte, 0, nameVectorLen)
216 for j := uint32(0); j < nameVectorLen; j++ {
217 offset := uintptr(j) * unsafe.Sizeof(byte(0))
218 value := *(*byte)(statSegPointer(nameVector, offset))
220 name = append(name, value)
225 return adapter.NameStat(data)
228 return adapter.EmptyStat("<none>")
232 // prevent recursion loops
233 if index != ^uint32(0) {
234 debugf("received symlink with defined item index")
237 i1, i2 := ss.getSymlinkIndexes(dirEntry)
238 // use first index to get the stats directory the symlink points to
239 header := ss.loadSharedHeader(ss.sharedHeader)
240 dirVector := ss.adjust(dirVector(&header.dirVector))
241 statSegDir2 := dirSegment(uintptr(dirVector) + uintptr(i1)*unsafe.Sizeof(statSegDirectoryEntryV2{}))
243 // retry with actual stats segment and use second index to get
244 // stats for the required item
245 return ss.CopyEntryData(statSegDir2, i2)
248 // TODO: monitor occurrences with metrics
249 debugf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name)
254 func (ss *statSegmentV2) UpdateEntryData(segment dirSegment, stat *adapter.Stat) error {
255 dirEntry := (*statSegDirectoryEntryV2)(segment)
256 switch (*stat).(type) {
257 case adapter.ScalarStat:
258 *stat = adapter.ScalarStat(dirEntry.unionData)
260 case adapter.ErrorStat:
261 dirVector := ss.getErrorVector()
262 if dirVector == nil {
263 debugf("error vector pointer is out of range for %s", dirEntry.name)
266 vecLen := *(*uint32)(vectorLen(dirVector))
267 var errData []adapter.Counter
268 for i := uint32(0); i < vecLen; i++ {
269 cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
270 cbVal := ss.adjust(vectorLen(cb))
272 debugf("error counter pointer out of range")
275 offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
276 val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
277 errData = append(errData, val)
279 *stat = adapter.ErrorStat(errData)
281 case adapter.SimpleCounterStat:
282 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
283 if dirVector == nil {
284 debugf("data vector pointer is out of range for %s", dirEntry.name)
287 vecLen := *(*uint32)(vectorLen(dirVector))
288 data := (*stat).(adapter.SimpleCounterStat)
289 if uint32(len(data)) != vecLen {
290 return ErrStatDataLenIncorrect
292 for i := uint32(0); i < vecLen; i++ {
293 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
294 counterVector := ss.adjust(vectorLen(counterVectorOffset))
295 if counterVector == nil {
296 debugf("counter (vector simple) pointer out of range")
299 counterVectorLength := *(*uint32)(vectorLen(counterVector))
300 data[i] = make([]adapter.Counter, counterVectorLength)
301 for j := uint32(0); j < counterVectorLength; j++ {
302 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
303 val := *(*adapter.Counter)(statSegPointer(counterVector, offset))
308 case adapter.CombinedCounterStat:
309 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
310 if dirVector == nil {
311 debugf("data vector pointer is out of range for %s", dirEntry.name)
314 vecLen := *(*uint32)(vectorLen(dirVector))
315 data := (*stat).(adapter.CombinedCounterStat)
316 for i := uint32(0); i < vecLen; i++ {
317 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
318 counterVector := ss.adjust(vectorLen(counterVectorOffset))
319 if counterVector == nil {
320 debugf("counter (vector combined) pointer out of range")
323 counterVectorLength := *(*uint32)(vectorLen(counterVector))
324 data[i] = make([]adapter.CombinedCounter, counterVectorLength)
325 for j := uint32(0); j < counterVectorLength; j++ {
326 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
327 val := *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
332 case adapter.NameStat:
333 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
334 if dirVector == nil {
335 debugf("data vector pointer is out of range for %s", dirEntry.name)
338 vecLen := *(*uint32)(vectorLen(dirVector))
339 data := (*stat).(adapter.NameStat)
340 for i := uint32(0); i < vecLen; i++ {
341 nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
342 if uintptr(nameVectorOffset) == 0 {
343 debugf("name vector out of range for %s (%v)", dirEntry.name, i)
346 nameVector := ss.adjust(vectorLen(nameVectorOffset))
347 if nameVector == nil {
348 debugf("name data pointer out of range")
351 nameVectorLen := *(*uint32)(vectorLen(nameVector))
353 if uint32(len(nameData))+1 != nameVectorLen {
354 return ErrStatDataLenIncorrect
356 for j := uint32(0); j < nameVectorLen; j++ {
357 offset := uintptr(j) * unsafe.Sizeof(byte(0))
358 value := *(*byte)(statSegPointer(nameVector, offset))
368 Log.Debugf("Unrecognized stat type %T for stat entry: %v", stat, dirEntry.name)
374 // Adjust data pointer using shared header and base and return
375 // the pointer to a data segment
376 func (ss *statSegmentV2) adjust(data dirVector) dirVector {
377 header := ss.loadSharedHeader(ss.sharedHeader)
378 adjusted := dirVector(uintptr(unsafe.Pointer(&ss.sharedHeader[0])) +
379 uintptr(*(*uint64)(data)) - uintptr(*(*uint64)(unsafe.Pointer(&header.base))))
380 if uintptr(unsafe.Pointer(&ss.sharedHeader[len(ss.sharedHeader)-1])) <= uintptr(adjusted) ||
381 uintptr(unsafe.Pointer(&ss.sharedHeader[0])) >= uintptr(adjusted) {
387 func (ss *statSegmentV2) getErrorVector() dirVector {
388 header := ss.loadSharedHeader(ss.sharedHeader)
389 return ss.adjust(dirVector(&header.errorVector))
392 func (ss *statSegmentV2) getSymlinkIndexes(dirEntry *statSegDirectoryEntryV2) (index1, index2 uint32) {
394 if err := binary.Write(&b, binary.LittleEndian, dirEntry.unionData); err != nil {
395 debugf("error getting symlink indexes for %s: %v", dirEntry.name, err)
398 if len(b.Bytes()) != 8 {
399 debugf("incorrect symlink union data length for %s: expected 8, got %d", dirEntry.name, len(b.Bytes()))
402 for i := range b.Bytes()[:4] {
403 index1 += uint32(b.Bytes()[i]) << (uint32(i) * 8)
405 for i := range b.Bytes()[4:] {
406 index2 += uint32(b.Bytes()[i+4]) << (uint32(i) * 8)