Fix compilation for VPP 19.01
[govpp.git] / adapter / vppapiclient / stat_client.go
1 // Copyright (c) 2018 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 // +build !windows,!darwin
16
17 package vppapiclient
18
19 /*
20 #cgo CFLAGS: -DPNG_DEBUG=1
21 #cgo LDFLAGS: -lvppapiclient
22
23 #include "stat_client_wrapper.h"
24 */
25 import "C"
26
27 import (
28         "errors"
29         "fmt"
30         "os"
31         "unsafe"
32
33         "git.fd.io/govpp.git/adapter"
34 )
35
36 var (
37         ErrStatDirBusy  = errors.New("stat dir busy")
38         ErrStatDumpBusy = errors.New("stat dump busy")
39 )
40
41 var (
42         // DefaultStatSocket is the default path for the VPP stat socket file.
43         DefaultStatSocket = "/run/vpp/stats.sock"
44 )
45
46 // global VPP stats API client, library vppapiclient only supports
47 // single connection at a time
48 var globalStatClient *statClient
49
50 // stubStatClient is the default implementation of StatsAPI.
51 type statClient struct {
52         socketName string
53 }
54
55 // NewStatClient returns new VPP stats API client.
56 func NewStatClient(socketName string) adapter.StatsAPI {
57         return &statClient{
58                 socketName: socketName,
59         }
60 }
61
62 func (c *statClient) Connect() error {
63         if globalStatClient != nil {
64                 return fmt.Errorf("already connected to stats API, disconnect first")
65         }
66
67         var sockName string
68         if c.socketName == "" {
69                 sockName = DefaultStatSocket
70         } else {
71                 sockName = c.socketName
72         }
73
74         rc := C.govpp_stat_connect(C.CString(sockName))
75         if rc != 0 {
76                 return fmt.Errorf("connecting to VPP stats API failed (rc=%v)", rc)
77         }
78
79         globalStatClient = c
80         return nil
81 }
82
83 func (c *statClient) Disconnect() error {
84         globalStatClient = nil
85
86         C.govpp_stat_disconnect()
87         return nil
88 }
89
90 func (c *statClient) ListStats(patterns ...string) (stats []string, err error) {
91         dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
92         if dir == nil {
93                 return nil, ErrStatDirBusy
94         }
95         defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
96
97         l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dir))
98         for i := 0; i < int(l); i++ {
99                 nameChar := C.govpp_stat_segment_dir_index_to_name(dir, C.uint32_t(i))
100                 stats = append(stats, C.GoString(nameChar))
101                 C.free(unsafe.Pointer(nameChar))
102         }
103
104         return stats, nil
105 }
106
107 func (c *statClient) DumpStats(patterns ...string) (stats []*adapter.StatEntry, err error) {
108         dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
109         if dir == nil {
110                 return nil, ErrStatDirBusy
111         }
112         defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
113
114         dump := C.govpp_stat_segment_dump(dir)
115         if dump == nil {
116                 return nil, ErrStatDumpBusy
117         }
118         defer C.govpp_stat_segment_data_free(dump)
119
120         l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dump))
121         for i := 0; i < int(l); i++ {
122                 v := C.govpp_stat_segment_dump_index(dump, C.int(i))
123                 nameChar := v.name
124                 name := C.GoString(nameChar)
125                 typ := adapter.StatType(C.govpp_stat_segment_data_type(&v))
126
127                 stat := &adapter.StatEntry{
128                         Name: name,
129                         Type: typ,
130                 }
131
132                 switch typ {
133                 case adapter.ScalarIndex:
134                         stat.Data = adapter.ScalarStat(C.govpp_stat_segment_data_get_scalar_value(&v))
135
136                 case adapter.ErrorIndex:
137                         stat.Data = adapter.ErrorStat(C.govpp_stat_segment_data_get_error_value(&v))
138
139                 case adapter.SimpleCounterVector:
140                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_simple_counter(&v))))
141                         vector := make([][]adapter.Counter, length)
142                         for k := 0; k < length; k++ {
143                                 for j := 0; j < int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_simple_counter_index(&v, C.int(k))))); j++ {
144                                         vector[k] = append(vector[k], adapter.Counter(C.govpp_stat_segment_data_get_simple_counter_index_value(&v, C.int(k), C.int(j))))
145                                 }
146                         }
147                         stat.Data = adapter.SimpleCounterStat(vector)
148
149                 case adapter.CombinedCounterVector:
150                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_combined_counter(&v))))
151                         vector := make([][]adapter.CombinedCounter, length)
152                         for k := 0; k < length; k++ {
153                                 for j := 0; j < int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_combined_counter_index(&v, C.int(k))))); j++ {
154                                         vector[k] = append(vector[k], adapter.CombinedCounter{
155                                                 Packets: adapter.Counter(C.govpp_stat_segment_data_get_combined_counter_index_packets(&v, C.int(k), C.int(j))),
156                                                 Bytes:   adapter.Counter(C.govpp_stat_segment_data_get_combined_counter_index_bytes(&v, C.int(k), C.int(j))),
157                                         })
158                                 }
159                         }
160                         stat.Data = adapter.CombinedCounterStat(vector)
161
162                 case adapter.NameVector:
163                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_name_vector(&v))))
164                         var vector []adapter.Name
165                         for k := 0; k < length; k++ {
166                                 s := C.govpp_stat_segment_data_get_name_vector_index(&v, C.int(k))
167                                 var name adapter.Name
168                                 if s != nil {
169                                         name = adapter.Name(C.GoString(s))
170                                 }
171                                 vector = append(vector, name)
172                         }
173                         stat.Data = adapter.NameStat(vector)
174
175                 default:
176                         fmt.Fprintf(os.Stderr, "invalid stat type: %v (%v)\n", typ, name)
177                         continue
178
179                 }
180
181                 stats = append(stats, stat)
182         }
183
184         return stats, nil
185 }
186
187 func convertStringSlice(strs []string) **C.uint8_t {
188         var arr **C.uint8_t
189         for _, str := range strs {
190                 arr = C.govpp_stat_segment_string_vector(arr, C.CString(str))
191         }
192         return arr
193 }