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,!novpp,!beyond18.10
20 #cgo CFLAGS: -DPNG_DEBUG=1
21 #cgo LDFLAGS: -lvppapiclient
23 #include "stat_client_wrapper.h"
32 "git.fd.io/govpp.git/adapter"
35 // global VPP stats API client, library vppapiclient only supports
36 // single connection at a time
37 var globalStatClient *statClient
39 // statClient is the default implementation of StatsAPI.
40 type statClient struct {
44 // NewStatClient returns new VPP stats API client.
45 func NewStatClient(socketName string) adapter.StatsAPI {
47 socketName: socketName,
51 func (c *statClient) Connect() error {
52 if globalStatClient != nil {
53 return fmt.Errorf("already connected to stats API, disconnect first")
57 if c.socketName == "" {
58 sockName = adapter.DefaultStatsSocket
60 sockName = c.socketName
63 if _, err := os.Stat(sockName); err != nil {
64 if os.IsNotExist(err) {
65 return fmt.Errorf("stats socket file %q does not exists, ensure that VPP is running with `statseg { ... }` section in config", sockName)
67 return fmt.Errorf("stats socket file error: %v", err)
70 rc := C.govpp_stat_connect(C.CString(sockName))
72 return fmt.Errorf("connecting to VPP stats API failed (rc=%v)", rc)
79 func (c *statClient) Disconnect() error {
80 globalStatClient = nil
82 C.govpp_stat_disconnect()
86 func (c *statClient) ListStats(patterns ...string) (stats []string, err error) {
87 dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
89 return nil, adapter.ErrStatsDataBusy
91 defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
93 l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dir))
94 for i := 0; i < int(l); i++ {
95 nameChar := C.govpp_stat_segment_dir_index_to_name(dir, C.uint32_t(i))
96 stats = append(stats, C.GoString(nameChar))
97 C.free(unsafe.Pointer(nameChar))
103 func (c *statClient) DumpStats(patterns ...string) (stats []adapter.StatEntry, err error) {
104 dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
106 return nil, adapter.ErrStatsDataBusy
108 defer C.govpp_stat_segment_vec_free(unsafe.Pointer(dir))
110 dump := C.govpp_stat_segment_dump(dir)
112 return nil, adapter.ErrStatsDataBusy
114 defer C.govpp_stat_segment_data_free(dump)
116 l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dump))
117 for i := 0; i < int(l); i++ {
118 v := C.govpp_stat_segment_dump_index(dump, C.int(i))
120 name := C.GoString(nameChar)
121 typ := adapter.StatType(C.govpp_stat_segment_data_type(&v))
123 stat := adapter.StatEntry{
129 case adapter.ScalarIndex:
130 stat.Data = adapter.ScalarStat(C.govpp_stat_segment_data_get_scalar_value(&v))
132 case adapter.ErrorIndex:
133 stat.Data = adapter.ErrorStat(C.govpp_stat_segment_data_get_error_value(&v))
135 case adapter.SimpleCounterVector:
136 length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_simple_counter(&v))))
137 vector := make([][]adapter.Counter, length)
138 for k := 0; k < length; k++ {
139 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++ {
140 vector[k] = append(vector[k], adapter.Counter(C.govpp_stat_segment_data_get_simple_counter_index_value(&v, C.int(k), C.int(j))))
143 stat.Data = adapter.SimpleCounterStat(vector)
145 case adapter.CombinedCounterVector:
146 length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_combined_counter(&v))))
147 vector := make([][]adapter.CombinedCounter, length)
148 for k := 0; k < length; k++ {
149 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++ {
150 vector[k] = append(vector[k], adapter.CombinedCounter([2]uint64{
151 uint64(C.govpp_stat_segment_data_get_combined_counter_index_packets(&v, C.int(k), C.int(j))),
152 uint64(C.govpp_stat_segment_data_get_combined_counter_index_bytes(&v, C.int(k), C.int(j))),
156 stat.Data = adapter.CombinedCounterStat(vector)
158 case adapter.NameVector:
159 length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_name_vector(&v))))
160 var vector []adapter.Name
161 for k := 0; k < length; k++ {
162 s := C.govpp_stat_segment_data_get_name_vector_index(&v, C.int(k))
163 var name adapter.Name
165 name = adapter.Name(C.GoString(s))
167 vector = append(vector, name)
169 stat.Data = adapter.NameStat(vector)
172 fmt.Fprintf(os.Stderr, "invalid stat type: %v (%v)\n", typ, name)
177 stats = append(stats, stat)
183 func (c *statClient) PrepareDir(prefixes ...string) (*adapter.StatDir, error) {
184 return nil, adapter.ErrNotImplemented
187 func (c *statClient) UpdateDir(dir *adapter.StatDir) error {
188 return adapter.ErrNotImplemented
191 func convertStringSlice(strs []string) **C.uint8_t {
193 for _, str := range strs {
194 arr = C.govpp_stat_segment_string_vector(arr, C.CString(str))