1 // Copyright (c) 2019 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.
22 "git.fd.io/govpp.git/adapter"
25 type statSegmentV1 struct {
30 type sharedHeaderV1 struct {
39 type statSegDirectoryEntryV1 struct {
40 directoryType statDirectoryType
41 // unionData can represent:
50 func newStatSegmentV1(data []byte, size int64) *statSegmentV1 {
51 return &statSegmentV1{
57 func (ss *statSegmentV1) loadSharedHeader(b []byte) (header sharedHeaderV1) {
58 h := (*sharedHeaderV1)(unsafe.Pointer(&b[0]))
59 return sharedHeaderV1{
60 version: atomic.LoadUint64(&h.version),
61 epoch: atomic.LoadInt64(&h.epoch),
62 inProgress: atomic.LoadInt64(&h.inProgress),
63 directoryOffset: atomic.LoadInt64(&h.directoryOffset),
64 errorOffset: atomic.LoadInt64(&h.errorOffset),
65 statsOffset: atomic.LoadInt64(&h.statsOffset),
69 func (ss *statSegmentV1) GetDirectoryVector() unsafe.Pointer {
70 dirOffset, _, _ := ss.getOffsets()
71 return unsafe.Pointer(&ss.sharedHeader[dirOffset])
74 func (ss *statSegmentV1) GetErrorVector() (unsafe.Pointer, error) {
75 return nil, fmt.Errorf("error vector is not defined for stats API v1")
78 func (ss *statSegmentV1) GetStatDirOnIndex(p unsafe.Pointer, index uint32) (unsafe.Pointer, statDirectoryName, statDirectoryType) {
79 statSegDir := unsafe.Pointer(uintptr(p) + uintptr(index)*unsafe.Sizeof(statSegDirectoryEntryV1{}))
80 dir := (*statSegDirectoryEntryV1)(statSegDir)
82 for n := 0; n < len(dir.name); n++ {
88 return statSegDir, name, dir.directoryType
91 func (ss *statSegmentV1) GetEpoch() (int64, bool) {
92 sh := ss.loadSharedHeader(ss.sharedHeader)
93 return sh.epoch, sh.inProgress != 0
96 func (ss *statSegmentV1) CopyEntryData(statSegDir unsafe.Pointer) adapter.Stat {
97 dirEntry := (*statSegDirectoryEntryV1)(statSegDir)
98 dirType := adapter.StatType(dirEntry.directoryType)
101 case statDirScalarIndex:
102 return adapter.ScalarStat(dirEntry.unionData)
104 case statDirErrorIndex:
105 if dirEntry.unionData == 0 {
106 debugf("offset invalid for %s", dirEntry.name)
108 } else if dirEntry.unionData >= uint64(len(ss.sharedHeader)) {
109 debugf("offset out of range for %s", dirEntry.name)
113 _, errOffset, _ := ss.getOffsets()
114 offsetVector := unsafe.Pointer(&ss.sharedHeader[errOffset])
116 var errData []adapter.Counter
118 vecLen := *(*uint32)(vectorLen(offsetVector))
119 for i := uint32(0); i < vecLen; i++ {
120 cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
121 offset := uintptr(cb) + uintptr(dirEntry.unionData)*unsafe.Sizeof(adapter.Counter(0))
122 debugf("error index, cb: %d, offset: %d", cb, offset)
123 val := *(*adapter.Counter)(statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), offset))
124 errData = append(errData, val)
126 return adapter.ErrorStat(errData)
128 case statDirCounterVectorSimple:
129 if dirEntry.unionData == 0 {
130 debugf("offset invalid for %s", dirEntry.name)
132 } else if dirEntry.unionData >= uint64(len(ss.sharedHeader)) {
133 debugf("offset out of range for %s", dirEntry.name)
137 vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
138 offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
140 data := make([][]adapter.Counter, vecLen)
141 for i := uint32(0); i < vecLen; i++ {
142 cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
143 counterVec := unsafe.Pointer(&ss.sharedHeader[uintptr(cb)])
144 vecLen2 := *(*uint32)(vectorLen(counterVec))
145 data[i] = make([]adapter.Counter, vecLen2)
146 for j := uint32(0); j < vecLen2; j++ {
147 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
148 val := *(*adapter.Counter)(statSegPointer(counterVec, offset))
152 return adapter.SimpleCounterStat(data)
154 case statDirCounterVectorCombined:
155 if dirEntry.unionData == 0 {
156 debugf("offset invalid for %s", dirEntry.name)
158 } else if dirEntry.unionData >= uint64(len(ss.sharedHeader)) {
159 debugf("offset out of range for %s", dirEntry.name)
163 vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
164 offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
166 data := make([][]adapter.CombinedCounter, vecLen)
167 for i := uint32(0); i < vecLen; i++ {
168 cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
169 counterVec := unsafe.Pointer(&ss.sharedHeader[uintptr(cb)])
170 vecLen2 := *(*uint32)(vectorLen(counterVec))
171 data[i] = make([]adapter.CombinedCounter, vecLen2)
172 for j := uint32(0); j < vecLen2; j++ {
173 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
174 val := *(*adapter.CombinedCounter)(statSegPointer(counterVec, offset))
178 return adapter.CombinedCounterStat(data)
180 case statDirNameVector:
181 if dirEntry.unionData == 0 {
182 debugf("offset invalid for %s", dirEntry.name)
184 } else if dirEntry.unionData >= uint64(len(ss.sharedHeader)) {
185 debugf("offset out of range for %s", dirEntry.name)
189 vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
190 offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
192 data := make([]adapter.Name, vecLen)
193 for i := uint32(0); i < vecLen; i++ {
194 cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
196 debugf("name vector out of range for %s (%v)", dirEntry.name, i)
199 nameVec := unsafe.Pointer(&ss.sharedHeader[cb])
200 vecLen2 := *(*uint32)(vectorLen(nameVec))
202 nameStr := make([]byte, 0, vecLen2)
203 for j := uint32(0); j < vecLen2; j++ {
204 offset := uintptr(j) * unsafe.Sizeof(byte(0))
205 val := *(*byte)(statSegPointer(nameVec, offset))
207 nameStr = append(nameStr, val)
212 return adapter.NameStat(data)
218 // TODO: monitor occurrences with metrics
219 debugf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name)
224 func (ss *statSegmentV1) UpdateEntryData(statSegDir unsafe.Pointer, stat *adapter.Stat) error {
225 dirEntry := (*statSegDirectoryEntryV1)(statSegDir)
226 switch (*stat).(type) {
227 case adapter.ScalarStat:
228 *stat = adapter.ScalarStat(dirEntry.unionData)
230 case adapter.ErrorStat:
231 if dirEntry.unionData == 0 {
232 debugf("offset invalid for %s", dirEntry.name)
234 } else if dirEntry.unionData >= uint64(len(ss.sharedHeader)) {
235 debugf("offset out of range for %s", dirEntry.name)
239 _, errOffset, _ := ss.getOffsets()
240 offsetVector := unsafe.Pointer(&ss.sharedHeader[errOffset])
242 var errData []adapter.Counter
244 vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[errOffset])))
245 for i := uint32(0); i < vecLen; i++ {
246 cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
247 offset := uintptr(cb) + uintptr(dirEntry.unionData)*unsafe.Sizeof(adapter.Counter(0))
248 val := *(*adapter.Counter)(statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), offset))
249 errData = append(errData, val)
251 *stat = adapter.ErrorStat(errData)
253 case adapter.SimpleCounterStat:
254 if dirEntry.unionData == 0 {
255 debugf("offset invalid for %s", dirEntry.name)
257 } else if dirEntry.unionData >= uint64(len(ss.sharedHeader)) {
258 debugf("offset out of range for %s", dirEntry.name)
262 vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
263 offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
265 data := (*stat).(adapter.SimpleCounterStat)
266 if uint32(len(data)) != vecLen {
267 return ErrStatDataLenIncorrect
269 for i := uint32(0); i < vecLen; i++ {
270 cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
271 counterVec := unsafe.Pointer(&ss.sharedHeader[uintptr(cb)])
272 vecLen2 := *(*uint32)(vectorLen(counterVec))
273 simpleData := data[i]
274 if uint32(len(simpleData)) != vecLen2 {
275 return ErrStatDataLenIncorrect
277 for j := uint32(0); j < vecLen2; j++ {
278 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
279 val := *(*adapter.Counter)(statSegPointer(counterVec, offset))
284 case adapter.CombinedCounterStat:
285 if dirEntry.unionData == 0 {
286 debugf("offset invalid for %s", dirEntry.name)
288 } else if dirEntry.unionData >= uint64(len(ss.sharedHeader)) {
289 debugf("offset out of range for %s", dirEntry.name)
293 vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
294 offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
296 data := (*stat).(adapter.CombinedCounterStat)
297 if uint32(len(data)) != vecLen {
298 return ErrStatDataLenIncorrect
300 for i := uint32(0); i < vecLen; i++ {
301 cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
302 counterVec := unsafe.Pointer(&ss.sharedHeader[uintptr(cb)])
303 vecLen2 := *(*uint32)(vectorLen(counterVec))
305 if uint32(len(combData)) != vecLen2 {
306 return ErrStatDataLenIncorrect
308 for j := uint32(0); j < vecLen2; j++ {
309 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
310 val := *(*adapter.CombinedCounter)(statSegPointer(counterVec, offset))
315 case adapter.NameStat:
316 if dirEntry.unionData == 0 {
317 debugf("offset invalid for %s", dirEntry.name)
319 } else if dirEntry.unionData >= uint64(len(ss.sharedHeader)) {
320 debugf("offset out of range for %s", dirEntry.name)
324 vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
325 offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
327 data := (*stat).(adapter.NameStat)
328 if uint32(len(data)) != vecLen {
329 return ErrStatDataLenIncorrect
331 for i := uint32(0); i < vecLen; i++ {
332 cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
336 nameVec := unsafe.Pointer(&ss.sharedHeader[cb])
337 vecLen2 := *(*uint32)(vectorLen(nameVec))
340 if uint32(len(nameData))+1 != vecLen2 {
341 return ErrStatDataLenIncorrect
343 for j := uint32(0); j < vecLen2; j++ {
344 offset := uintptr(j) * unsafe.Sizeof(byte(0))
345 val := *(*byte)(statSegPointer(nameVec, offset))
355 Log.Debugf("Unrecognized stat type %T for stat entry: %v", stat, dirEntry.name)
361 // Get offsets for various types of data
362 func (ss *statSegmentV1) getOffsets() (dir, err, stat int64) {
363 sh := ss.loadSharedHeader(ss.sharedHeader)
364 return sh.directoryOffset, sh.errorOffset, sh.statsOffset