1 // Copyright (c) 2018 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.
15 // +build !windows,!darwin
20 #cgo CFLAGS: -DPNG_DEBUG=1
21 #cgo LDFLAGS: -lvppapiclient
26 #include <arpa/inet.h>
27 #include <vpp-api/client/vppapiclient.h> // VPP has to be installed!
28 #include <vpp-api/client/stat_client.h>
31 govpp_stat_connect(char *socket_name)
33 return stat_segment_connect(socket_name);
37 govpp_stat_disconnect()
39 stat_segment_disconnect();
43 govpp_stat_segment_ls(uint8_t **pattern)
45 return stat_segment_ls(pattern);
49 govpp_stat_segment_vec_len(void *vec)
51 return stat_segment_vec_len(vec);
55 govpp_stat_segment_vec_free(void *vec)
57 stat_segment_vec_free(vec);
61 govpp_stat_segment_dir_index_to_name(uint32_t *dir, uint32_t index)
63 return stat_segment_index_to_name(dir[index]);
66 static stat_segment_data_t*
67 govpp_stat_segment_dump(uint32_t *counter_vec)
69 return stat_segment_dump(counter_vec);
72 static stat_segment_data_t
73 govpp_stat_segment_dump_index(stat_segment_data_t *data, int index)
79 govpp_stat_segment_data_type(stat_segment_data_t *data)
85 govpp_stat_segment_data_get_scalar_value(stat_segment_data_t *data)
87 return data->scalar_value;
91 govpp_stat_segment_data_get_error_value(stat_segment_data_t *data)
93 return data->error_value;
97 govpp_stat_segment_data_get_simple_counter(stat_segment_data_t *data)
99 return data->simple_counter_vec;
103 govpp_stat_segment_data_get_simple_counter_index(stat_segment_data_t *data, int index)
105 return data->simple_counter_vec[index];
109 govpp_stat_segment_data_get_simple_counter_index_value(stat_segment_data_t *data, int index, int index2)
111 return data->simple_counter_vec[index][index2];
114 static vlib_counter_t**
115 govpp_stat_segment_data_get_combined_counter(stat_segment_data_t *data)
117 return data->combined_counter_vec;
120 static vlib_counter_t*
121 govpp_stat_segment_data_get_combined_counter_index(stat_segment_data_t *data, int index)
123 return data->combined_counter_vec[index];
127 govpp_stat_segment_data_get_combined_counter_index_packets(stat_segment_data_t *data, int index, int index2)
129 return data->combined_counter_vec[index][index2].packets;
133 govpp_stat_segment_data_get_combined_counter_index_bytes(stat_segment_data_t *data, int index, int index2)
135 return data->combined_counter_vec[index][index2].bytes;
139 govpp_stat_segment_data_get_name_vector(stat_segment_data_t *data)
141 return data->name_vector; // VPP 19.04 is required!
145 govpp_stat_segment_data_get_name_vector_index(stat_segment_data_t *data, int index)
147 return data->name_vector[index]; // VPP 19.04 is required!
151 govpp_stat_segment_data_free(stat_segment_data_t *data)
153 stat_segment_data_free(data);
157 govpp_stat_segment_string_vector(uint8_t ** string_vector, char *string)
159 return stat_segment_string_vector(string_vector, string);
169 "git.fd.io/govpp.git/adapter"
173 ErrStatDirBusy = errors.New("stat dir busy")
174 ErrStatDumpBusy = errors.New("stat dump busy")
178 // DefaultStatSocket is the default path for the VPP stat socket file.
179 DefaultStatSocket = "/run/vpp/stats.sock"
182 // global VPP stats API client, library vppapiclient only supports
183 // single connection at a time
184 var globalStatClient *statClient
186 // stubStatClient is the default implementation of StatsAPI.
187 type statClient struct {
191 // NewStatClient returns new VPP stats API client.
192 func NewStatClient(socketName string) adapter.StatsAPI {
194 socketName: socketName,
198 func (c *statClient) Connect() error {
199 if globalStatClient != nil {
200 return fmt.Errorf("already connected to stats API, disconnect first")
204 if c.socketName == "" {
205 sockName = DefaultStatSocket
207 sockName = c.socketName
210 rc := C.govpp_stat_connect(C.CString(sockName))
212 return fmt.Errorf("connecting to VPP stats API failed (rc=%v)", rc)
219 func (c *statClient) Disconnect() error {
220 globalStatClient = nil
222 C.govpp_stat_disconnect()
226 func (c *statClient) ListStats(patterns ...string) (stats []string, err error) {
227 dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
229 return nil, ErrStatDirBusy
231 defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
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))
243 func (c *statClient) DumpStats(patterns ...string) (stats []*adapter.StatEntry, err error) {
244 dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
246 return nil, ErrStatDirBusy
248 defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
250 dump := C.govpp_stat_segment_dump(dir)
252 return nil, ErrStatDumpBusy
254 defer C.govpp_stat_segment_data_free(dump)
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))
260 name := C.GoString(nameChar)
261 typ := adapter.StatType(C.govpp_stat_segment_data_type(&v))
263 stat := &adapter.StatEntry{
269 case adapter.ScalarIndex:
270 stat.Data = adapter.ScalarStat(C.govpp_stat_segment_data_get_scalar_value(&v))
272 case adapter.ErrorIndex:
273 stat.Data = adapter.ErrorStat(C.govpp_stat_segment_data_get_error_value(&v))
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))))
283 stat.Data = adapter.SimpleCounterStat(vector)
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))),
296 stat.Data = adapter.CombinedCounterStat(vector)
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
305 name = adapter.Name(C.GoString(s))
307 vector = append(vector, name)
309 stat.Data = adapter.NameStat(vector)
312 fmt.Fprintf(os.Stderr, "invalid stat type: %v (%v)\n", typ, name)
317 stats = append(stats, stat)
323 func convertStringSlice(strs []string) **C.uint8_t {
325 for _, str := range strs {
326 arr = C.govpp_stat_segment_string_vector(arr, C.CString(str))