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 typ := getStatType(dirEntry.directoryType, ss.getErrorVector() != nil)
96 // skip zero pointer value
97 if typ != adapter.ScalarIndex && typ != adapter.Empty && dirEntry.unionData == 0 {
98 debugf("data pointer not defined for %s", dirEntry.name)
103 case adapter.ScalarIndex:
104 return adapter.ScalarStat(dirEntry.unionData)
106 case adapter.ErrorIndex:
107 dirVector := ss.getErrorVector()
108 if dirVector == nil {
109 debugf("error vector pointer is out of range for %s", dirEntry.name)
112 vecLen := *(*uint32)(vectorLen(dirVector))
113 var errData []adapter.Counter
114 for i := uint32(0); i < vecLen; i++ {
115 cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
116 cbVal := ss.adjust(vectorLen(cb))
118 debugf("error counter pointer out of range")
121 offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
122 val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
123 errData = append(errData, val)
125 return adapter.ErrorStat(errData)
127 case adapter.SimpleCounterVector:
128 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
129 if dirVector == nil {
130 debugf("data vector pointer is out of range for %s", dirEntry.name)
133 vecLen := *(*uint32)(vectorLen(dirVector))
134 data := make([][]adapter.Counter, vecLen)
135 for i := uint32(0); i < vecLen; i++ {
136 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
137 counterVector := ss.adjust(vectorLen(counterVectorOffset))
138 if counterVector == nil {
139 debugf("counter (vector simple) pointer out of range")
142 counterVectorLength := *(*uint32)(vectorLen(counterVector))
143 if index == ^uint32(0) {
144 data[i] = make([]adapter.Counter, counterVectorLength)
145 for j := uint32(0); j < counterVectorLength; j++ {
146 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
147 data[i][j] = *(*adapter.Counter)(statSegPointer(counterVector, offset))
150 data[i] = make([]adapter.Counter, 1) // expect single value
151 for j := uint32(0); j < counterVectorLength; j++ {
152 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
154 data[i][0] = *(*adapter.Counter)(statSegPointer(counterVector, offset))
160 return adapter.SimpleCounterStat(data)
162 case adapter.CombinedCounterVector:
163 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
164 if dirVector == nil {
165 debugf("data vector pointer is out of range for %s", dirEntry.name)
168 vecLen := *(*uint32)(vectorLen(dirVector))
169 data := make([][]adapter.CombinedCounter, vecLen)
170 for i := uint32(0); i < vecLen; i++ {
171 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
172 counterVector := ss.adjust(vectorLen(counterVectorOffset))
173 if counterVector == nil {
174 debugf("counter (vector combined) pointer out of range")
177 counterVectorLength := *(*uint32)(vectorLen(counterVector))
178 if index == ^uint32(0) {
179 data[i] = make([]adapter.CombinedCounter, counterVectorLength)
180 for j := uint32(0); j < counterVectorLength; j++ {
181 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
182 data[i][j] = *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
185 data[i] = make([]adapter.CombinedCounter, 1) // expect single value pair
186 for j := uint32(0); j < counterVectorLength; j++ {
187 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
189 data[i][0] = *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
195 return adapter.CombinedCounterStat(data)
197 case adapter.NameVector:
198 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
199 if dirVector == nil {
200 debugf("data vector pointer is out of range for %s", dirEntry.name)
203 vecLen := *(*uint32)(vectorLen(dirVector))
204 data := make([]adapter.Name, vecLen)
205 for i := uint32(0); i < vecLen; i++ {
206 nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
207 if uintptr(nameVectorOffset) == 0 {
208 debugf("name vector out of range for %s (%v)", dirEntry.name, i)
211 nameVector := ss.adjust(vectorLen(nameVectorOffset))
212 if nameVector == nil {
213 debugf("name data pointer out of range")
216 nameVectorLen := *(*uint32)(vectorLen(nameVector))
217 name := make([]byte, 0, nameVectorLen)
218 for j := uint32(0); j < nameVectorLen; j++ {
219 offset := uintptr(j) * unsafe.Sizeof(byte(0))
220 value := *(*byte)(statSegPointer(nameVector, offset))
222 name = append(name, value)
227 return adapter.NameStat(data)
230 return adapter.EmptyStat("<none>")
233 case adapter.Symlink:
234 // prevent recursion loops
235 if index != ^uint32(0) {
236 debugf("received symlink with defined item index")
239 i1, i2 := ss.getSymlinkIndexes(dirEntry)
240 // use first index to get the stats directory the symlink points to
241 header := ss.loadSharedHeader(ss.sharedHeader)
242 dirVector := ss.adjust(dirVector(&header.dirVector))
243 statSegDir2 := dirSegment(uintptr(dirVector) + uintptr(i1)*unsafe.Sizeof(statSegDirectoryEntryV2{}))
245 // retry with actual stats segment and use second index to get
246 // stats for the required item
247 return ss.CopyEntryData(statSegDir2, i2)
250 // TODO: monitor occurrences with metrics
251 debugf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name)
256 func (ss *statSegmentV2) UpdateEntryData(segment dirSegment, stat *adapter.Stat) error {
257 dirEntry := (*statSegDirectoryEntryV2)(segment)
258 switch (*stat).(type) {
259 case adapter.ScalarStat:
260 *stat = adapter.ScalarStat(dirEntry.unionData)
262 case adapter.ErrorStat:
263 dirVector := ss.getErrorVector()
264 if dirVector == nil {
265 debugf("error vector pointer is out of range for %s", dirEntry.name)
268 vecLen := *(*uint32)(vectorLen(dirVector))
269 var errData []adapter.Counter
270 for i := uint32(0); i < vecLen; i++ {
271 cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
272 cbVal := ss.adjust(vectorLen(cb))
274 debugf("error counter pointer out of range")
277 offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
278 val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
279 errData = append(errData, val)
281 *stat = adapter.ErrorStat(errData)
283 case adapter.SimpleCounterStat:
284 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
285 if dirVector == nil {
286 debugf("data vector pointer is out of range for %s", dirEntry.name)
289 vecLen := *(*uint32)(vectorLen(dirVector))
290 data := (*stat).(adapter.SimpleCounterStat)
291 if uint32(len(data)) != vecLen {
292 return ErrStatDataLenIncorrect
294 for i := uint32(0); i < vecLen; i++ {
295 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
296 counterVector := ss.adjust(vectorLen(counterVectorOffset))
297 if counterVector == nil {
298 debugf("counter (vector simple) pointer out of range")
301 counterVectorLength := *(*uint32)(vectorLen(counterVector))
302 data[i] = make([]adapter.Counter, counterVectorLength)
303 for j := uint32(0); j < counterVectorLength; j++ {
304 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
305 val := *(*adapter.Counter)(statSegPointer(counterVector, offset))
310 case adapter.CombinedCounterStat:
311 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
312 if dirVector == nil {
313 debugf("data vector pointer is out of range for %s", dirEntry.name)
316 vecLen := *(*uint32)(vectorLen(dirVector))
317 data := (*stat).(adapter.CombinedCounterStat)
318 for i := uint32(0); i < vecLen; i++ {
319 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
320 counterVector := ss.adjust(vectorLen(counterVectorOffset))
321 if counterVector == nil {
322 debugf("counter (vector combined) pointer out of range")
325 counterVectorLength := *(*uint32)(vectorLen(counterVector))
326 data[i] = make([]adapter.CombinedCounter, counterVectorLength)
327 for j := uint32(0); j < counterVectorLength; j++ {
328 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
329 val := *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
334 case adapter.NameStat:
335 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
336 if dirVector == nil {
337 debugf("data vector pointer is out of range for %s", dirEntry.name)
340 vecLen := *(*uint32)(vectorLen(dirVector))
341 data := (*stat).(adapter.NameStat)
342 for i := uint32(0); i < vecLen; i++ {
343 nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
344 if uintptr(nameVectorOffset) == 0 {
345 debugf("name vector out of range for %s (%v)", dirEntry.name, i)
348 nameVector := ss.adjust(vectorLen(nameVectorOffset))
349 if nameVector == nil {
350 debugf("name data pointer out of range")
353 nameVectorLen := *(*uint32)(vectorLen(nameVector))
355 if uint32(len(nameData))+1 != nameVectorLen {
356 return ErrStatDataLenIncorrect
358 for j := uint32(0); j < nameVectorLen; j++ {
359 offset := uintptr(j) * unsafe.Sizeof(byte(0))
360 value := *(*byte)(statSegPointer(nameVector, offset))
370 Log.Debugf("Unrecognized stat type %T for stat entry: %v", stat, dirEntry.name)
376 // Adjust data pointer using shared header and base and return
377 // the pointer to a data segment
378 func (ss *statSegmentV2) adjust(data dirVector) dirVector {
379 header := ss.loadSharedHeader(ss.sharedHeader)
380 adjusted := dirVector(uintptr(unsafe.Pointer(&ss.sharedHeader[0])) +
381 uintptr(*(*uint64)(data)) - uintptr(*(*uint64)(unsafe.Pointer(&header.base))))
382 if uintptr(unsafe.Pointer(&ss.sharedHeader[len(ss.sharedHeader)-1])) <= uintptr(adjusted) ||
383 uintptr(unsafe.Pointer(&ss.sharedHeader[0])) >= uintptr(adjusted) {
389 func (ss *statSegmentV2) getErrorVector() dirVector {
390 header := ss.loadSharedHeader(ss.sharedHeader)
391 return ss.adjust(dirVector(&header.errorVector))
394 func (ss *statSegmentV2) getSymlinkIndexes(dirEntry *statSegDirectoryEntryV2) (index1, index2 uint32) {
396 if err := binary.Write(&b, binary.LittleEndian, dirEntry.unionData); err != nil {
397 debugf("error getting symlink indexes for %s: %v", dirEntry.name, err)
400 if len(b.Bytes()) != 8 {
401 debugf("incorrect symlink union data length for %s: expected 8, got %d", dirEntry.name, len(b.Bytes()))
404 for i := range b.Bytes()[:4] {
405 index1 += uint32(b.Bytes()[i]) << (uint32(i) * 8)
407 for i := range b.Bytes()[4:] {
408 index2 += uint32(b.Bytes()[i+4]) << (uint32(i) * 8)