Check if dir ls/dump returns nil
[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 <stdlib.h>
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <arpa/inet.h>
27 #include <vpp-api/client/vppapiclient.h>
28 #include <vpp-api/client/stat_client.h>
29
30 static int
31 govpp_stat_connect(char *socket_name)
32 {
33         return stat_segment_connect(socket_name);
34 }
35
36 static void
37 govpp_stat_disconnect()
38 {
39     stat_segment_disconnect();
40 }
41
42 static uint32_t*
43 govpp_stat_segment_ls(uint8_t **pattern)
44 {
45         return stat_segment_ls(pattern);
46 }
47
48 static int
49 govpp_stat_segment_vec_len(void *vec)
50 {
51         return stat_segment_vec_len(vec);
52 }
53
54 static void
55 govpp_stat_segment_vec_free(void *vec)
56 {
57         stat_segment_vec_free(vec);
58 }
59
60 static char*
61 govpp_stat_segment_dir_index_to_name(uint32_t *dir, uint32_t index)
62 {
63         return stat_segment_index_to_name(dir[index]);
64 }
65
66 static stat_segment_data_t*
67 govpp_stat_segment_dump(uint32_t *counter_vec)
68 {
69         return stat_segment_dump(counter_vec);
70 }
71
72 static stat_segment_data_t
73 govpp_stat_segment_dump_index(stat_segment_data_t *data, int index)
74 {
75         return data[index];
76 }
77
78 static int
79 govpp_stat_segment_data_type(stat_segment_data_t *data)
80 {
81         return data->type;
82 }
83
84 static double
85 govpp_stat_segment_data_get_scalar_value(stat_segment_data_t *data)
86 {
87         return data->scalar_value;
88 }
89
90 static double
91 govpp_stat_segment_data_get_error_value(stat_segment_data_t *data)
92 {
93         return data->error_value;
94 }
95
96 static uint64_t**
97 govpp_stat_segment_data_get_simple_counter(stat_segment_data_t *data)
98 {
99         return data->simple_counter_vec;
100 }
101
102 static uint64_t*
103 govpp_stat_segment_data_get_simple_counter_index(stat_segment_data_t *data, int index)
104 {
105         return data->simple_counter_vec[index];
106 }
107
108 static uint64_t
109 govpp_stat_segment_data_get_simple_counter_index_value(stat_segment_data_t *data, int index, int index2)
110 {
111         return data->simple_counter_vec[index][index2];
112 }
113
114 static vlib_counter_t**
115 govpp_stat_segment_data_get_combined_counter(stat_segment_data_t *data)
116 {
117         return data->combined_counter_vec;
118 }
119
120 static vlib_counter_t*
121 govpp_stat_segment_data_get_combined_counter_index(stat_segment_data_t *data, int index)
122 {
123         return data->combined_counter_vec[index];
124 }
125
126 static uint64_t
127 govpp_stat_segment_data_get_combined_counter_index_packets(stat_segment_data_t *data, int index, int index2)
128 {
129         return data->combined_counter_vec[index][index2].packets;
130 }
131
132 static uint64_t
133 govpp_stat_segment_data_get_combined_counter_index_bytes(stat_segment_data_t *data, int index, int index2)
134 {
135         return data->combined_counter_vec[index][index2].bytes;
136 }
137
138 static uint8_t**
139 govpp_stat_segment_data_get_name_vector(stat_segment_data_t *data)
140 {
141         return data->name_vector;
142 }
143
144 static char*
145 govpp_stat_segment_data_get_name_vector_index(stat_segment_data_t *data, int index)
146 {
147         return data->name_vector[index];
148 }
149
150 static void
151 govpp_stat_segment_data_free(stat_segment_data_t *data)
152 {
153         stat_segment_data_free(data);
154 }
155
156 static uint8_t**
157 govpp_stat_segment_string_vector(uint8_t ** string_vector, char *string)
158 {
159         return stat_segment_string_vector(string_vector, string);
160 }
161 */
162 import "C"
163 import (
164         "errors"
165         "fmt"
166         "os"
167         "unsafe"
168
169         "git.fd.io/govpp.git/adapter"
170 )
171
172 var (
173         ErrStatDirBusy  = errors.New("stat dir busy")
174         ErrStatDumpBusy = errors.New("stat dump busy")
175 )
176
177 var (
178         // DefaultStatSocket is the default path for the VPP stat socket file.
179         DefaultStatSocket = "/run/vpp/stats.sock"
180 )
181
182 // global VPP stats API client, library vppapiclient only supports
183 // single connection at a time
184 var globalStatClient *statClient
185
186 // stubStatClient is the default implementation of StatsAPI.
187 type statClient struct {
188         socketName string
189 }
190
191 // NewStatClient returns new VPP stats API client.
192 func NewStatClient(socketName string) adapter.StatsAPI {
193         return &statClient{
194                 socketName: socketName,
195         }
196 }
197
198 func (c *statClient) Connect() error {
199         if globalStatClient != nil {
200                 return fmt.Errorf("already connected to stats API, disconnect first")
201         }
202
203         var sockName string
204         if c.socketName == "" {
205                 sockName = DefaultStatSocket
206         } else {
207                 sockName = c.socketName
208         }
209
210         rc := C.govpp_stat_connect(C.CString(sockName))
211         if rc != 0 {
212                 return fmt.Errorf("connecting to VPP stats API failed (rc=%v)", rc)
213         }
214
215         globalStatClient = c
216         return nil
217 }
218
219 func (c *statClient) Disconnect() error {
220         globalStatClient = nil
221
222         C.govpp_stat_disconnect()
223         return nil
224 }
225
226 func (c *statClient) ListStats(patterns ...string) (stats []string, err error) {
227         dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
228         if dir == nil {
229                 return nil, ErrStatDirBusy
230         }
231         defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
232
233         l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dir))
234         for i := 0; i < int(l); i++ {
235                 nameChar := C.govpp_stat_segment_dir_index_to_name(dir, C.uint32_t(i))
236                 stats = append(stats, C.GoString(nameChar))
237                 C.free(unsafe.Pointer(nameChar))
238         }
239
240         return stats, nil
241 }
242
243 func (c *statClient) DumpStats(patterns ...string) (stats []*adapter.StatEntry, err error) {
244         dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
245         if dir == nil {
246                 return nil, ErrStatDirBusy
247         }
248         defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
249
250         dump := C.govpp_stat_segment_dump(dir)
251         if dump == nil {
252                 return nil, ErrStatDumpBusy
253         }
254         defer C.govpp_stat_segment_data_free(dump)
255
256         l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dump))
257         for i := 0; i < int(l); i++ {
258                 v := C.govpp_stat_segment_dump_index(dump, C.int(i))
259                 nameChar := v.name
260                 name := C.GoString(nameChar)
261                 typ := adapter.StatType(C.govpp_stat_segment_data_type(&v))
262
263                 stat := &adapter.StatEntry{
264                         Name: name,
265                         Type: typ,
266                 }
267
268                 switch typ {
269                 case adapter.ScalarIndex:
270                         stat.Data = adapter.ScalarStat(C.govpp_stat_segment_data_get_scalar_value(&v))
271
272                 case adapter.ErrorIndex:
273                         stat.Data = adapter.ErrorStat(C.govpp_stat_segment_data_get_error_value(&v))
274
275                 case adapter.SimpleCounterVector:
276                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_simple_counter(&v))))
277                         vector := make([][]adapter.Counter, length)
278                         for k := 0; k < length; k++ {
279                                 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++ {
280                                         vector[k] = append(vector[k], adapter.Counter(C.govpp_stat_segment_data_get_simple_counter_index_value(&v, C.int(k), C.int(j))))
281                                 }
282                         }
283                         stat.Data = adapter.SimpleCounterStat(vector)
284
285                 case adapter.CombinedCounterVector:
286                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_combined_counter(&v))))
287                         vector := make([][]adapter.CombinedCounter, length)
288                         for k := 0; k < length; k++ {
289                                 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++ {
290                                         vector[k] = append(vector[k], adapter.CombinedCounter{
291                                                 Packets: adapter.Counter(C.govpp_stat_segment_data_get_combined_counter_index_packets(&v, C.int(k), C.int(j))),
292                                                 Bytes:   adapter.Counter(C.govpp_stat_segment_data_get_combined_counter_index_bytes(&v, C.int(k), C.int(j))),
293                                         })
294                                 }
295                         }
296                         stat.Data = adapter.CombinedCounterStat(vector)
297
298                 case adapter.NameVector:
299                         length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_name_vector(&v))))
300                         var vector []adapter.Name
301                         for k := 0; k < length; k++ {
302                                 s := C.govpp_stat_segment_data_get_name_vector_index(&v, C.int(k))
303                                 var name adapter.Name
304                                 if s != nil {
305                                         name = adapter.Name(C.GoString(s))
306                                 }
307                                 vector = append(vector, name)
308                         }
309                         stat.Data = adapter.NameStat(vector)
310
311                 default:
312                         fmt.Fprintf(os.Stderr, "invalid stat type: %v (%v)\n", typ, name)
313                         continue
314
315                 }
316
317                 stats = append(stats, stat)
318         }
319
320         return stats, nil
321 }
322
323 func convertStringSlice(strs []string) **C.uint8_t {
324         var arr **C.uint8_t
325         for _, str := range strs {
326                 arr = C.govpp_stat_segment_string_vector(arr, C.CString(str))
327         }
328         return arr
329 }