8 "git.fd.io/govpp.git/adapter"
9 "git.fd.io/govpp.git/api"
13 CounterStatsPrefix = "/err/"
15 SystemStatsPrefix = "/sys/"
16 SystemStats_VectorRate = SystemStatsPrefix + "vector_rate"
17 SystemStats_InputRate = SystemStatsPrefix + "input_rate"
18 SystemStats_LastUpdate = SystemStatsPrefix + "last_update"
19 SystemStats_LastStatsClear = SystemStatsPrefix + "last_stats_clear"
20 SystemStats_Heartbeat = SystemStatsPrefix + "heartbeat"
22 NodeStatsPrefix = "/sys/node/"
23 NodeStats_Names = NodeStatsPrefix + "names"
24 NodeStats_Clocks = NodeStatsPrefix + "clocks"
25 NodeStats_Vectors = NodeStatsPrefix + "vectors"
26 NodeStats_Calls = NodeStatsPrefix + "calls"
27 NodeStats_Suspends = NodeStatsPrefix + "suspends"
29 InterfaceStatsPrefix = "/if/"
30 InterfaceStats_Names = InterfaceStatsPrefix + "names"
31 InterfaceStats_Drops = InterfaceStatsPrefix + "drops"
32 InterfaceStats_Punt = InterfaceStatsPrefix + "punt"
33 InterfaceStats_IP4 = InterfaceStatsPrefix + "ip4"
34 InterfaceStats_IP6 = InterfaceStatsPrefix + "ip6"
35 InterfaceStats_RxNoBuf = InterfaceStatsPrefix + "rx-no-buf"
36 InterfaceStats_RxMiss = InterfaceStatsPrefix + "rx-miss"
37 InterfaceStats_RxError = InterfaceStatsPrefix + "rx-error"
38 InterfaceStats_TxError = InterfaceStatsPrefix + "tx-error"
39 InterfaceStats_Rx = InterfaceStatsPrefix + "rx"
40 InterfaceStats_RxUnicast = InterfaceStatsPrefix + "rx-unicast"
41 InterfaceStats_RxMulticast = InterfaceStatsPrefix + "rx-multicast"
42 InterfaceStats_RxBroadcast = InterfaceStatsPrefix + "rx-broadcast"
43 InterfaceStats_Tx = InterfaceStatsPrefix + "tx"
44 InterfaceStats_TxUnicastMiss = InterfaceStatsPrefix + "tx-unicast-miss"
45 InterfaceStats_TxMulticast = InterfaceStatsPrefix + "tx-multicast"
46 InterfaceStats_TxBroadcast = InterfaceStatsPrefix + "tx-broadcast"
48 NetworkStatsPrefix = "/net/"
49 // TODO: network stats
50 NetworkStats_RouteTo = NetworkStatsPrefix + "route/to"
51 NetworkStats_RouteVia = NetworkStatsPrefix + "route/via"
52 NetworkStats_MRoute = NetworkStatsPrefix + "mroute"
53 NetworkStats_Adjacency = NetworkStatsPrefix + "adjacency"
56 type StatsConnection struct {
57 statsClient adapter.StatsAPI
59 connected uint32 // non-zero if the adapter is connected to VPP
62 func newStatsConnection(stats adapter.StatsAPI) *StatsConnection {
63 return &StatsConnection{
68 // Connect connects to Stats API using specified adapter and returns a connection handle.
69 // This call blocks until it is either connected, or an error occurs.
70 // Only one connection attempt will be performed.
71 func ConnectStats(stats adapter.StatsAPI) (*StatsConnection, error) {
72 c := newStatsConnection(stats)
74 if err := c.connectClient(); err != nil {
81 func (c *StatsConnection) connectClient() error {
82 log.Debug("Connecting to stats..")
84 if err := c.statsClient.Connect(); err != nil {
88 log.Debugf("Connected to stats.")
90 // store connected state
91 atomic.StoreUint32(&c.connected, 1)
96 // Disconnect disconnects from Stats API and releases all connection-related resources.
97 func (c *StatsConnection) Disconnect() {
102 if c.statsClient != nil {
107 func (c *StatsConnection) disconnectClient() {
108 if atomic.CompareAndSwapUint32(&c.connected, 1, 0) {
109 c.statsClient.Disconnect()
113 // GetSystemStats retrieves VPP system stats.
114 func (c *StatsConnection) GetSystemStats() (*api.SystemStats, error) {
115 stats, err := c.statsClient.DumpStats(SystemStatsPrefix)
120 sysStats := &api.SystemStats{}
122 for _, stat := range stats {
124 case SystemStats_VectorRate:
125 sysStats.VectorRate = scalarStatToFloat64(stat.Data)
126 case SystemStats_InputRate:
127 sysStats.InputRate = scalarStatToFloat64(stat.Data)
128 case SystemStats_LastUpdate:
129 sysStats.LastUpdate = scalarStatToFloat64(stat.Data)
130 case SystemStats_LastStatsClear:
131 sysStats.LastStatsClear = scalarStatToFloat64(stat.Data)
132 case SystemStats_Heartbeat:
133 sysStats.Heartbeat = scalarStatToFloat64(stat.Data)
140 // GetErrorStats retrieves VPP error stats.
141 func (c *StatsConnection) GetErrorStats(names ...string) (*api.ErrorStats, error) {
142 var patterns []string
144 patterns = make([]string, len(names))
145 for i, name := range names {
146 patterns[i] = CounterStatsPrefix + name
149 // retrieve all error counters by default
150 patterns = []string{CounterStatsPrefix}
152 stats, err := c.statsClient.DumpStats(patterns...)
157 var errorStats = &api.ErrorStats{}
159 for _, stat := range stats {
160 statName := strings.TrimPrefix(stat.Name, CounterStatsPrefix)
162 /* TODO: deal with stats that contain '/' in node/counter name
163 parts := strings.Split(statName, "/")
164 var nodeName, counterName string
168 counterName = parts[1]
170 nodeName = parts[0] + parts[1]
171 counterName = parts[2]
174 errorStats.Errors = append(errorStats.Errors, api.ErrorCounter{
175 CounterName: statName,
176 Value: errorStatToUint64(stat.Data),
180 return errorStats, nil
183 // GetNodeStats retrieves VPP per node stats.
184 func (c *StatsConnection) GetNodeStats() (*api.NodeStats, error) {
185 stats, err := c.statsClient.DumpStats(NodeStatsPrefix)
190 nodeStats := &api.NodeStats{}
191 var setPerNode = func(perNode []uint64, fn func(c *api.NodeCounters, v uint64)) {
192 if nodeStats.Nodes == nil {
193 nodeStats.Nodes = make([]api.NodeCounters, len(perNode))
194 for i := range perNode {
195 nodeStats.Nodes[i].NodeIndex = uint32(i)
198 for i, v := range perNode {
199 nodeCounters := nodeStats.Nodes[i]
201 nodeStats.Nodes[i] = nodeCounters
205 for _, stat := range stats {
207 case NodeStats_Names:
208 if names, ok := stat.Data.(adapter.NameStat); !ok {
209 return nil, fmt.Errorf("invalid stat type for %s", stat.Name)
211 if nodeStats.Nodes == nil {
212 nodeStats.Nodes = make([]api.NodeCounters, len(names))
213 for i := range names {
214 nodeStats.Nodes[i].NodeIndex = uint32(i)
217 for i, name := range names {
218 nodeStats.Nodes[i].NodeName = string(name)
221 case NodeStats_Clocks:
222 setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
225 case NodeStats_Vectors:
226 setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
229 case NodeStats_Calls:
230 setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
233 case NodeStats_Suspends:
234 setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
240 return nodeStats, nil
243 // GetInterfaceStats retrieves VPP per interface stats.
244 func (c *StatsConnection) GetInterfaceStats() (*api.InterfaceStats, error) {
245 stats, err := c.statsClient.DumpStats(InterfaceStatsPrefix)
250 ifStats := &api.InterfaceStats{}
252 var setPerIf = func(perIf []uint64, fn func(c *api.InterfaceCounters, v uint64)) {
253 if ifStats.Interfaces == nil {
254 ifStats.Interfaces = make([]api.InterfaceCounters, len(perIf))
255 for i := range perIf {
256 ifStats.Interfaces[i].InterfaceIndex = uint32(i)
259 for i, v := range perIf {
260 ifCounters := ifStats.Interfaces[i]
262 ifStats.Interfaces[i] = ifCounters
266 for _, stat := range stats {
268 case InterfaceStats_Names:
269 if names, ok := stat.Data.(adapter.NameStat); !ok {
270 return nil, fmt.Errorf("invalid stat type for %s", stat.Name)
272 if ifStats.Interfaces == nil {
273 ifStats.Interfaces = make([]api.InterfaceCounters, len(names))
274 for i := range names {
275 ifStats.Interfaces[i].InterfaceIndex = uint32(i)
278 for i, name := range names {
279 ifStats.Interfaces[i].InterfaceName = string(name)
282 case InterfaceStats_Drops:
283 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
286 case InterfaceStats_Punt:
287 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
290 case InterfaceStats_IP4:
291 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
294 case InterfaceStats_IP6:
295 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
298 case InterfaceStats_RxNoBuf:
299 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
302 case InterfaceStats_RxMiss:
303 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
306 case InterfaceStats_RxError:
307 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
310 case InterfaceStats_TxError:
311 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
314 case InterfaceStats_Rx:
315 per := reduceCombinedCounterStat(stat.Data)
316 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
319 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
322 case InterfaceStats_RxUnicast:
323 per := reduceCombinedCounterStat(stat.Data)
324 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
327 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
330 case InterfaceStats_RxMulticast:
331 per := reduceCombinedCounterStat(stat.Data)
332 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
335 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
338 case InterfaceStats_RxBroadcast:
339 per := reduceCombinedCounterStat(stat.Data)
340 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
343 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
346 case InterfaceStats_Tx:
347 per := reduceCombinedCounterStat(stat.Data)
348 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
351 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
354 case InterfaceStats_TxUnicastMiss:
355 per := reduceCombinedCounterStat(stat.Data)
356 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
357 c.TxUnicastMiss[0] = v
359 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
360 c.TxUnicastMiss[1] = v
362 case InterfaceStats_TxMulticast:
363 per := reduceCombinedCounterStat(stat.Data)
364 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
367 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
370 case InterfaceStats_TxBroadcast:
371 per := reduceCombinedCounterStat(stat.Data)
372 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
375 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
384 func scalarStatToFloat64(stat adapter.Stat) float64 {
385 if s, ok := stat.(adapter.ScalarStat); ok {
391 func errorStatToUint64(stat adapter.Stat) uint64 {
392 if s, ok := stat.(adapter.ErrorStat); ok {
398 func reduceSimpleCounterStat(stat adapter.Stat) []uint64 {
399 if s, ok := stat.(adapter.SimpleCounterStat); ok {
403 var per = make([]uint64, len(s[0]))
404 for _, w := range s {
405 for i, n := range w {
414 func reduceCombinedCounterStat(stat adapter.Stat) [2][]uint64 {
415 if s, ok := stat.(adapter.CombinedCounterStat); ok {
417 return [2][]uint64{{}, {}}
419 var perPackets = make([]uint64, len(s[0]))
420 var perBytes = make([]uint64, len(s[0]))
421 for _, w := range s {
422 for i, n := range w {
423 perPackets[i] += uint64(n.Packets)
424 perBytes[i] += uint64(n.Bytes)
427 return [2][]uint64{perPackets, perBytes}