Change module name to go.fd.io/govpp
[govpp.git] / adapter / statsclient / stat_segment_api.go
1 //  Copyright (c) 2020 Cisco and/or its affiliates.
2 //
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:
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 package statsclient
16
17 import (
18         "fmt"
19         "sync/atomic"
20         "time"
21         "unsafe"
22
23         "go.fd.io/govpp/adapter"
24 )
25
26 var (
27         // ErrStatDataLenIncorrect is returned when stat data does not match vector
28         // length of a respective data directory
29         ErrStatDataLenIncorrect = fmt.Errorf("stat data length incorrect")
30 )
31
32 var (
33         MaxWaitInProgress    = time.Millisecond * 100
34         CheckDelayInProgress = time.Microsecond * 10
35 )
36
37 const (
38         minVersion = 1
39         maxVersion = 2
40 )
41
42 var dirTypeMapping = map[dirType]adapter.StatType{
43         1: adapter.ScalarIndex,
44         2: adapter.SimpleCounterVector,
45         3: adapter.CombinedCounterVector,
46         4: adapter.NameVector,
47         5: adapter.Empty,
48         6: adapter.Symlink,
49 }
50
51 var dirTypeMappingLegacy = map[dirType]adapter.StatType{
52         1: adapter.ScalarIndex,
53         2: adapter.SimpleCounterVector,
54         3: adapter.CombinedCounterVector,
55         4: adapter.ErrorIndex,
56         5: adapter.NameVector,
57         6: adapter.Empty,
58         7: adapter.Symlink,
59 }
60
61 type (
62         dirVector  unsafe.Pointer
63         dirSegment unsafe.Pointer
64         dirName    []byte
65         dirType    int32
66 )
67
68 // statSegment represents common API for every stats API version
69 type statSegment interface {
70         // GetDirectoryVector returns pointer to memory where the beginning
71         // of the data directory is located.
72         GetDirectoryVector() dirVector
73
74         // GetStatDirOnIndex accepts directory vector and particular index.
75         // Returns pointer to the beginning of the segment. Also the directory
76         // name as [128]byte and the directory type is returned for easy use
77         // without needing to know the exact segment version.
78         //
79         // Note that if the index is equal to 0, the result pointer points to
80         // the same memory address as the argument.
81         GetStatDirOnIndex(v dirVector, index uint32) (dirSegment, dirName, adapter.StatType)
82
83         // GetEpoch re-loads stats header and returns current epoch
84         //and 'inProgress' value
85         GetEpoch() (int64, bool)
86
87         // CopyEntryData accepts pointer to a directory segment and returns adapter.Stat
88         // based on directory type populated with data. The index is an optional parameter
89         // (used by symlinks) returning stats for item on the given index only.
90         // Use ^uint32(0) as an empty index (since 0 is a valid value).
91         CopyEntryData(segment dirSegment, index uint32) adapter.Stat
92
93         // UpdateEntryData accepts pointer to a directory segment with data, and stat
94         // segment to update
95         UpdateEntryData(segment dirSegment, s *adapter.Stat) error
96 }
97
98 // vecHeader represents a vector header
99 type vecHeader struct {
100         length     uint64
101         vectorData [0]uint8
102 }
103
104 func getVersion(data []byte) uint64 {
105         type apiVersion struct {
106                 value uint64
107         }
108         header := (*apiVersion)(unsafe.Pointer(&data[0]))
109         version := &apiVersion{
110                 value: atomic.LoadUint64(&header.value),
111         }
112         debugf("stats API version loaded: %d", version.value)
113         return version.value
114 }
115
116 func vectorLen(v dirVector) dirVector {
117         vec := *(*vecHeader)(unsafe.Pointer(uintptr(v) - unsafe.Sizeof(uint64(0))))
118         return dirVector(&vec.length)
119 }
120
121 func getStatType(dirTypeNum dirType, useLegacyMapping bool) (dirTyp adapter.StatType) {
122         var exists bool
123         if useLegacyMapping {
124                 dirTyp, exists = dirTypeMappingLegacy[dirTypeNum]
125         } else {
126                 dirTyp, exists = dirTypeMapping[dirTypeNum]
127         }
128         if exists {
129                 return dirTyp
130         }
131         return adapter.Unknown
132 }
133
134 //go:nosplit
135 func statSegPointer(v dirVector, offset uintptr) dirVector {
136         return dirVector(uintptr(v) + offset)
137 }