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.
21 "git.fd.io/govpp.git/adapter"
24 type statSegmentV2 struct {
29 type sharedHeaderV2 struct {
34 dirVector unsafe.Pointer
35 errorVector unsafe.Pointer
38 type statSegDirectoryEntryV2 struct {
40 // unionData can represent:
48 func newStatSegmentV2(data []byte, size int64) *statSegmentV2 {
49 return &statSegmentV2{
55 func (ss *statSegmentV2) loadSharedHeader(b []byte) (header sharedHeaderV2) {
56 h := (*sharedHeaderV2)(unsafe.Pointer(&b[0]))
57 return sharedHeaderV2{
58 version: atomic.LoadUint64(&h.version),
59 base: atomic.LoadPointer(&h.base),
60 epoch: atomic.LoadInt64(&h.epoch),
61 inProgress: atomic.LoadInt64(&h.inProgress),
62 dirVector: atomic.LoadPointer(&h.dirVector),
63 errorVector: atomic.LoadPointer(&h.errorVector),
67 func (ss *statSegmentV2) GetDirectoryVector() dirVector {
68 header := ss.loadSharedHeader(ss.sharedHeader)
69 return ss.adjust(dirVector(&header.dirVector))
72 func (ss *statSegmentV2) GetStatDirOnIndex(v dirVector, index uint32) (dirSegment, dirName, dirType) {
73 statSegDir := dirSegment(uintptr(v) + uintptr(index)*unsafe.Sizeof(statSegDirectoryEntryV2{}))
74 dir := (*statSegDirectoryEntryV2)(statSegDir)
76 for n := 0; n < len(dir.name); n++ {
82 return statSegDir, name, dir.directoryType
85 func (ss *statSegmentV2) GetEpoch() (int64, bool) {
86 sh := ss.loadSharedHeader(ss.sharedHeader)
87 return sh.epoch, sh.inProgress != 0
90 func (ss *statSegmentV2) CopyEntryData(segment dirSegment) adapter.Stat {
91 dirEntry := (*statSegDirectoryEntryV2)(segment)
92 if dirEntry.unionData == 0 {
93 debugf("data value or pointer not defined for %s", dirEntry.name)
97 switch adapter.StatType(dirEntry.directoryType) {
98 case statDirScalarIndex:
99 return adapter.ScalarStat(dirEntry.unionData)
101 case statDirErrorIndex:
102 dirVector := ss.getErrorVector()
103 if dirVector == nil {
104 debugf("error vector pointer is out of range for %s", dirEntry.name)
107 vecLen := *(*uint32)(vectorLen(dirVector))
108 var errData []adapter.Counter
109 for i := uint32(0); i < vecLen; i++ {
110 cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
111 cbVal := ss.adjust(vectorLen(cb))
113 debugf("error counter pointer out of range")
116 offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
117 val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
118 errData = append(errData, val)
120 return adapter.ErrorStat(errData)
122 case statDirCounterVectorSimple:
123 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
124 if dirVector == nil {
125 debugf("data vector pointer is out of range for %s", dirEntry.name)
128 vecLen := *(*uint32)(vectorLen(dirVector))
129 data := make([][]adapter.Counter, vecLen)
130 for i := uint32(0); i < vecLen; i++ {
131 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
132 counterVector := ss.adjust(vectorLen(counterVectorOffset))
133 if counterVector == nil {
134 debugf("counter (vector simple) pointer out of range")
137 counterVectorLength := *(*uint32)(vectorLen(counterVector))
138 data[i] = make([]adapter.Counter, counterVectorLength)
139 for j := uint32(0); j < counterVectorLength; j++ {
140 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
141 val := *(*adapter.Counter)(statSegPointer(counterVector, offset))
145 return adapter.SimpleCounterStat(data)
147 case statDirCounterVectorCombined:
148 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
149 if dirVector == nil {
150 debugf("data vector pointer is out of range for %s", dirEntry.name)
153 vecLen := *(*uint32)(vectorLen(dirVector))
154 data := make([][]adapter.CombinedCounter, vecLen)
155 for i := uint32(0); i < vecLen; i++ {
156 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
157 counterVector := ss.adjust(vectorLen(counterVectorOffset))
158 if counterVector == nil {
159 debugf("counter (vector combined) pointer out of range")
162 counterVectorLength := *(*uint32)(vectorLen(counterVector))
163 data[i] = make([]adapter.CombinedCounter, counterVectorLength)
164 for j := uint32(0); j < counterVectorLength; j++ {
165 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
166 val := *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
170 return adapter.CombinedCounterStat(data)
172 case statDirNameVector:
173 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
174 if dirVector == nil {
175 debugf("data vector pointer is out of range for %s", dirEntry.name)
178 vecLen := *(*uint32)(vectorLen(dirVector))
179 data := make([]adapter.Name, vecLen)
180 for i := uint32(0); i < vecLen; i++ {
181 nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
182 if uintptr(nameVectorOffset) == 0 {
183 debugf("name vector out of range for %s (%v)", dirEntry.name, i)
186 nameVector := ss.adjust(vectorLen(nameVectorOffset))
187 if nameVector == nil {
188 debugf("name data pointer out of range")
191 nameVectorLen := *(*uint32)(vectorLen(nameVector))
192 name := make([]byte, 0, nameVectorLen)
193 for j := uint32(0); j < nameVectorLen; j++ {
194 offset := uintptr(j) * unsafe.Sizeof(byte(0))
195 value := *(*byte)(statSegPointer(nameVector, offset))
197 name = append(name, value)
202 return adapter.NameStat(data)
205 return adapter.EmptyStat("<none>")
209 // TODO: monitor occurrences with metrics
210 debugf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name)
215 func (ss *statSegmentV2) UpdateEntryData(segment dirSegment, stat *adapter.Stat) error {
216 dirEntry := (*statSegDirectoryEntryV2)(segment)
217 switch (*stat).(type) {
218 case adapter.ScalarStat:
219 *stat = adapter.ScalarStat(dirEntry.unionData)
221 case adapter.ErrorStat:
222 dirVector := ss.getErrorVector()
223 if dirVector == nil {
224 debugf("error vector pointer is out of range for %s", dirEntry.name)
227 vecLen := *(*uint32)(vectorLen(dirVector))
228 var errData []adapter.Counter
229 for i := uint32(0); i < vecLen; i++ {
230 cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
231 cbVal := ss.adjust(vectorLen(cb))
233 debugf("error counter pointer out of range")
236 offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
237 val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
238 errData = append(errData, val)
240 *stat = adapter.ErrorStat(errData)
242 case adapter.SimpleCounterStat:
243 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
244 if dirVector == nil {
245 debugf("data vector pointer is out of range for %s", dirEntry.name)
248 vecLen := *(*uint32)(vectorLen(dirVector))
249 data := (*stat).(adapter.SimpleCounterStat)
250 if uint32(len(data)) != vecLen {
251 return ErrStatDataLenIncorrect
253 for i := uint32(0); i < vecLen; i++ {
254 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
255 counterVector := ss.adjust(vectorLen(counterVectorOffset))
256 if counterVector == nil {
257 debugf("counter (vector simple) pointer out of range")
260 counterVectorLength := *(*uint32)(vectorLen(counterVector))
261 data[i] = make([]adapter.Counter, counterVectorLength)
262 for j := uint32(0); j < counterVectorLength; j++ {
263 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
264 val := *(*adapter.Counter)(statSegPointer(counterVector, offset))
269 case adapter.CombinedCounterStat:
270 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
271 if dirVector == nil {
272 debugf("data vector pointer is out of range for %s", dirEntry.name)
275 vecLen := *(*uint32)(vectorLen(dirVector))
276 data := (*stat).(adapter.CombinedCounterStat)
277 for i := uint32(0); i < vecLen; i++ {
278 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
279 counterVector := ss.adjust(vectorLen(counterVectorOffset))
280 if counterVector == nil {
281 debugf("counter (vector combined) pointer out of range")
284 counterVectorLength := *(*uint32)(vectorLen(counterVector))
285 data[i] = make([]adapter.CombinedCounter, counterVectorLength)
286 for j := uint32(0); j < counterVectorLength; j++ {
287 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
288 val := *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
293 case adapter.NameStat:
294 dirVector := ss.adjust(dirVector(&dirEntry.unionData))
295 if dirVector == nil {
296 debugf("data vector pointer is out of range for %s", dirEntry.name)
299 vecLen := *(*uint32)(vectorLen(dirVector))
300 data := (*stat).(adapter.NameStat)
301 for i := uint32(0); i < vecLen; i++ {
302 nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
303 if uintptr(nameVectorOffset) == 0 {
304 debugf("name vector out of range for %s (%v)", dirEntry.name, i)
307 nameVector := ss.adjust(vectorLen(nameVectorOffset))
308 if nameVector == nil {
309 debugf("name data pointer out of range")
312 nameVectorLen := *(*uint32)(vectorLen(nameVector))
314 if uint32(len(nameData))+1 != nameVectorLen {
315 return ErrStatDataLenIncorrect
317 for j := uint32(0); j < nameVectorLen; j++ {
318 offset := uintptr(j) * unsafe.Sizeof(byte(0))
319 value := *(*byte)(statSegPointer(nameVector, offset))
329 Log.Debugf("Unrecognized stat type %T for stat entry: %v", stat, dirEntry.name)
335 // Adjust data pointer using shared header and base and return
336 // the pointer to a data segment
337 func (ss *statSegmentV2) adjust(data dirVector) dirVector {
338 header := ss.loadSharedHeader(ss.sharedHeader)
339 adjusted := dirVector(uintptr(unsafe.Pointer(&ss.sharedHeader[0])) +
340 uintptr(*(*uint64)(data)) - uintptr(*(*uint64)(unsafe.Pointer(&header.base))))
341 if uintptr(unsafe.Pointer(&ss.sharedHeader[len(ss.sharedHeader)-1])) <= uintptr(adjusted) ||
342 uintptr(unsafe.Pointer(&ss.sharedHeader[0])) >= uintptr(adjusted) {
348 func (ss *statSegmentV2) getErrorVector() dirVector {
349 header := ss.loadSharedHeader(ss.sharedHeader)
350 return ss.adjust(dirVector(&header.errorVector))