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.
25 "github.com/ftrvxmtrx/fd"
27 "git.fd.io/govpp.git/adapter"
31 maxWaitInProgress = time.Second * 1
34 type statSegDirectoryEntry struct {
35 directoryType statDirectoryType
36 // unionData can represent: offset, index or value
42 type statDirectoryType int32
44 func (t statDirectoryType) String() string {
45 return adapter.StatType(t).String()
48 type statSegment struct {
55 func (c *statSegment) connect(sockName string) error {
56 addr := &net.UnixAddr{
61 Log.Debugf("connecting to: %v", addr)
63 conn, err := net.DialUnix(addr.Net, nil, addr)
65 Log.Warnf("connecting to socket %s failed: %s", addr, err)
69 if err := conn.Close(); err != nil {
70 Log.Warnf("closing socket failed: %v", err)
74 Log.Debugf("connected to socket")
76 files, err := fd.Get(conn, 1, nil)
78 return fmt.Errorf("getting file descriptor over socket failed: %v", err)
81 return fmt.Errorf("no files received over socket")
84 for _, f := range files {
85 if err := f.Close(); err != nil {
86 Log.Warnf("closing file %s failed: %v", f.Name(), err)
91 Log.Debugf("received %d files over socket", len(files))
102 Log.Debugf("fd: name=%v size=%v", info.Name(), size)
104 data, err := syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
106 Log.Warnf("mapping shared memory failed: %v", err)
107 return fmt.Errorf("mapping shared memory failed: %v", err)
110 Log.Debugf("successfuly mapped shared memory")
112 c.sharedHeader = data
115 header := c.readHeader()
116 Log.Debugf("stat segment header: %+v", header)
118 // older VPP (19.04) did not have version in stat segment header
119 // we try to provide fallback support by skipping it in header
120 if header.version > MaxVersion && header.inProgress > 1 && header.epoch == 0 {
121 h := c.readHeaderOld()
122 Log.Infof("statsclient: falling back to old stat segment version (VPP 19.04): %+v", h)
129 func (c *statSegment) disconnect() error {
130 if err := syscall.Munmap(c.sharedHeader); err != nil {
131 Log.Warnf("unmapping shared memory failed: %v", err)
132 return fmt.Errorf("unmapping shared memory failed: %v", err)
135 Log.Debugf("successfuly unmapped shared memory")
140 type sharedHeaderBase struct {
143 directoryOffset int64
148 type statSegSharedHeader struct {
153 func (c *statSegment) readHeaderOld() (header statSegSharedHeader) {
154 h := (*sharedHeaderBase)(unsafe.Pointer(&c.sharedHeader[0]))
156 header.epoch = atomic.LoadInt64(&h.epoch)
157 header.inProgress = atomic.LoadInt64(&h.inProgress)
158 header.directoryOffset = atomic.LoadInt64(&h.directoryOffset)
159 header.errorOffset = atomic.LoadInt64(&h.errorOffset)
160 header.statsOffset = atomic.LoadInt64(&h.statsOffset)
164 func (c *statSegment) readHeader() (header statSegSharedHeader) {
165 h := (*statSegSharedHeader)(unsafe.Pointer(&c.sharedHeader[0]))
166 header.version = atomic.LoadUint64(&h.version)
167 header.epoch = atomic.LoadInt64(&h.epoch)
168 header.inProgress = atomic.LoadInt64(&h.inProgress)
169 header.directoryOffset = atomic.LoadInt64(&h.directoryOffset)
170 header.errorOffset = atomic.LoadInt64(&h.errorOffset)
171 header.statsOffset = atomic.LoadInt64(&h.statsOffset)
175 func (c *statSegment) readVersion() uint64 {
179 header := (*statSegSharedHeader)(unsafe.Pointer(&c.sharedHeader[0]))
180 version := atomic.LoadUint64(&header.version)
184 func (c *statSegment) readEpoch() (int64, bool) {
186 h := c.readHeaderOld()
187 return h.epoch, h.inProgress != 0
189 header := (*statSegSharedHeader)(unsafe.Pointer(&c.sharedHeader[0]))
190 epoch := atomic.LoadInt64(&header.epoch)
191 inprog := atomic.LoadInt64(&header.inProgress)
192 return epoch, inprog != 0
195 func (c *statSegment) readOffsets() (dir, err, stat int64) {
197 h := c.readHeaderOld()
198 return h.directoryOffset, h.errorOffset, h.statsOffset
200 header := (*statSegSharedHeader)(unsafe.Pointer(&c.sharedHeader[0]))
201 dirOffset := atomic.LoadInt64(&header.directoryOffset)
202 errOffset := atomic.LoadInt64(&header.errorOffset)
203 statOffset := atomic.LoadInt64(&header.statsOffset)
204 return dirOffset, errOffset, statOffset
207 type statSegAccess struct {
211 func (c *statSegment) accessStart() *statSegAccess {
212 epoch, inprog := c.readEpoch()
215 if time.Since(t) > maxWaitInProgress {
218 epoch, inprog = c.readEpoch()
220 return &statSegAccess{
225 func (c *statSegment) accessEnd(acc *statSegAccess) bool {
226 epoch, inprog := c.readEpoch()
227 if acc.epoch != epoch || inprog {
233 type vecHeader struct {
238 func vectorLen(v unsafe.Pointer) uint64 {
239 vec := *(*vecHeader)(unsafe.Pointer(uintptr(v) - unsafe.Sizeof(uintptr(0))))
244 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
245 return unsafe.Pointer(uintptr(p) + x)