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 {
39 directoryType statDirectoryType
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() unsafe.Pointer {
68 header := ss.loadSharedHeader(ss.sharedHeader)
69 return ss.adjust(unsafe.Pointer(&header.dirVector))
72 func (ss *statSegmentV2) GetStatDirOnIndex(p unsafe.Pointer, index uint32) (unsafe.Pointer, statDirectoryName, statDirectoryType) {
73 statSegDir := unsafe.Pointer(uintptr(p) + 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(statSegDir unsafe.Pointer) adapter.Stat {
91 dirEntry := (*statSegDirectoryEntryV2)(statSegDir)
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))
120 return adapter.ErrorStat(errData)
122 case statDirCounterVectorSimple:
123 dirVector := ss.adjust(unsafe.Pointer(&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(unsafe.Pointer(&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(unsafe.Pointer(&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)
208 // TODO: monitor occurrences with metrics
209 debugf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name)
214 func (ss *statSegmentV2) UpdateEntryData(statSegDir unsafe.Pointer, stat *adapter.Stat) error {
215 dirEntry := (*statSegDirectoryEntryV2)(statSegDir)
216 switch (*stat).(type) {
217 case adapter.ScalarStat:
218 *stat = adapter.ScalarStat(dirEntry.unionData)
220 case adapter.ErrorStat:
221 dirVector := ss.getErrorVector()
222 if dirVector == nil {
223 debugf("error vector pointer is out of range for %s", dirEntry.name)
226 vecLen := *(*uint32)(vectorLen(dirVector))
227 var errData adapter.Counter
228 for i := uint32(0); i < vecLen; i++ {
229 cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
230 cbVal := ss.adjust(vectorLen(cb))
232 debugf("error counter pointer out of range")
235 offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
236 val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
239 *stat = adapter.ErrorStat(errData)
241 case adapter.SimpleCounterStat:
242 dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
243 if dirVector == nil {
244 debugf("data vector pointer is out of range for %s", dirEntry.name)
247 vecLen := *(*uint32)(vectorLen(dirVector))
248 data := (*stat).(adapter.SimpleCounterStat)
249 if uint32(len(data)) != vecLen {
250 return ErrStatDataLenIncorrect
252 for i := uint32(0); i < vecLen; i++ {
253 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
254 counterVector := ss.adjust(vectorLen(counterVectorOffset))
255 if counterVector == nil {
256 debugf("counter (vector simple) pointer out of range")
259 counterVectorLength := *(*uint32)(vectorLen(counterVector))
260 data[i] = make([]adapter.Counter, counterVectorLength)
261 for j := uint32(0); j < counterVectorLength; j++ {
262 offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
263 val := *(*adapter.Counter)(statSegPointer(counterVector, offset))
268 case adapter.CombinedCounterStat:
269 dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
270 if dirVector == nil {
271 debugf("data vector pointer is out of range for %s", dirEntry.name)
274 vecLen := *(*uint32)(vectorLen(dirVector))
275 data := (*stat).(adapter.CombinedCounterStat)
276 for i := uint32(0); i < vecLen; i++ {
277 counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
278 counterVector := ss.adjust(vectorLen(counterVectorOffset))
279 if counterVector == nil {
280 debugf("counter (vector combined) pointer out of range")
283 counterVectorLength := *(*uint32)(vectorLen(counterVector))
284 data[i] = make([]adapter.CombinedCounter, counterVectorLength)
285 for j := uint32(0); j < counterVectorLength; j++ {
286 offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
287 val := *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
292 case adapter.NameStat:
293 dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
294 if dirVector == nil {
295 debugf("data vector pointer is out of range for %s", dirEntry.name)
298 vecLen := *(*uint32)(vectorLen(dirVector))
299 data := (*stat).(adapter.NameStat)
300 for i := uint32(0); i < vecLen; i++ {
301 nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
302 if uintptr(nameVectorOffset) == 0 {
303 debugf("name vector out of range for %s (%v)", dirEntry.name, i)
306 nameVector := ss.adjust(vectorLen(nameVectorOffset))
307 if nameVector == nil {
308 debugf("name data pointer out of range")
311 nameVectorLen := *(*uint32)(vectorLen(nameVector))
313 if uint32(len(nameData))+1 != nameVectorLen {
314 return ErrStatDataLenIncorrect
316 for j := uint32(0); j < nameVectorLen; j++ {
317 offset := uintptr(j) * unsafe.Sizeof(byte(0))
318 value := *(*byte)(statSegPointer(nameVector, offset))
328 Log.Debugf("Unrecognized stat type %T for stat entry: %v", stat, dirEntry.name)
334 // Adjust data pointer using shared header and base and return
335 // the pointer to a data segment
336 func (ss *statSegmentV2) adjust(data unsafe.Pointer) unsafe.Pointer {
337 header := ss.loadSharedHeader(ss.sharedHeader)
338 adjusted := unsafe.Pointer(uintptr(unsafe.Pointer(&ss.sharedHeader[0])) +
339 uintptr(*(*uint64)(data)) - uintptr(*(*uint64)(unsafe.Pointer(&header.base))))
340 if uintptr(unsafe.Pointer(&ss.sharedHeader[len(ss.sharedHeader)-1])) <= uintptr(adjusted) ||
341 uintptr(unsafe.Pointer(&ss.sharedHeader[0])) >= uintptr(adjusted) {
347 func (ss *statSegmentV2) getErrorVector() unsafe.Pointer {
348 header := ss.loadSharedHeader(ss.sharedHeader)
349 return ss.adjust(unsafe.Pointer(&header.errorVector))