7 "git.fd.io/govpp.git/adapter"
8 "git.fd.io/govpp.git/api"
12 CounterStatsPrefix = "/err/"
14 SystemStatsPrefix = "/sys/"
15 SystemStats_VectorRate = SystemStatsPrefix + "vector_rate"
16 SystemStats_InputRate = SystemStatsPrefix + "input_rate"
17 SystemStats_LastUpdate = SystemStatsPrefix + "last_update"
18 SystemStats_LastStatsClear = SystemStatsPrefix + "last_stats_clear"
19 SystemStats_Heartbeat = SystemStatsPrefix + "heartbeat"
21 NodeStatsPrefix = "/sys/node/"
22 NodeStats_Clocks = NodeStatsPrefix + "clocks"
23 NodeStats_Vectors = NodeStatsPrefix + "vectors"
24 NodeStats_Calls = NodeStatsPrefix + "calls"
25 NodeStats_Suspends = NodeStatsPrefix + "suspends"
27 InterfaceStatsPrefix = "/if/"
28 InterfaceStats_Drops = InterfaceStatsPrefix + "drops"
29 InterfaceStats_Punt = InterfaceStatsPrefix + "punt"
30 InterfaceStats_IP4 = InterfaceStatsPrefix + "ip4"
31 InterfaceStats_IP6 = InterfaceStatsPrefix + "ip6"
32 InterfaceStats_RxNoBuf = InterfaceStatsPrefix + "rx-no-buf"
33 InterfaceStats_RxMiss = InterfaceStatsPrefix + "rx-miss"
34 InterfaceStats_RxError = InterfaceStatsPrefix + "rx-error"
35 InterfaceStats_TxError = InterfaceStatsPrefix + "tx-error"
36 InterfaceStats_Rx = InterfaceStatsPrefix + "rx"
37 InterfaceStats_RxUnicast = InterfaceStatsPrefix + "rx-unicast"
38 InterfaceStats_RxMulticast = InterfaceStatsPrefix + "rx-multicast"
39 InterfaceStats_RxBroadcast = InterfaceStatsPrefix + "rx-broadcast"
40 InterfaceStats_Tx = InterfaceStatsPrefix + "tx"
41 InterfaceStats_TxUnicastMiss = InterfaceStatsPrefix + "tx-unicast-miss"
42 InterfaceStats_TxMulticast = InterfaceStatsPrefix + "tx-multicast"
43 InterfaceStats_TxBroadcast = InterfaceStatsPrefix + "tx-broadcast"
45 NetworkStatsPrefix = "/net/"
46 NetworkStats_RouteTo = NetworkStatsPrefix + "route/to"
47 NetworkStats_RouteVia = NetworkStatsPrefix + "route/via"
48 NetworkStats_MRoute = NetworkStatsPrefix + "mroute"
49 NetworkStats_Adjacency = NetworkStatsPrefix + "adjacency"
52 type StatsConnection struct {
53 statsClient adapter.StatsAPI
55 connected uint32 // non-zero if the adapter is connected to VPP
58 func newStatsConnection(stats adapter.StatsAPI) *StatsConnection {
59 return &StatsConnection{
64 // Connect connects to Stats API using specified adapter and returns a connection handle.
65 // This call blocks until it is either connected, or an error occurs.
66 // Only one connection attempt will be performed.
67 func ConnectStats(stats adapter.StatsAPI) (*StatsConnection, error) {
68 c := newStatsConnection(stats)
70 if err := c.connectClient(); err != nil {
77 func (c *StatsConnection) connectClient() error {
78 log.Debug("Connecting to stats..")
80 if err := c.statsClient.Connect(); err != nil {
84 log.Debugf("Connected to stats.")
86 // store connected state
87 atomic.StoreUint32(&c.connected, 1)
92 // Disconnect disconnects from Stats API and releases all connection-related resources.
93 func (c *StatsConnection) Disconnect() {
98 if c.statsClient != nil {
103 func (c *StatsConnection) disconnectClient() {
104 if atomic.CompareAndSwapUint32(&c.connected, 1, 0) {
105 c.statsClient.Disconnect()
109 // GetSystemStats retrieves VPP system stats.
110 func (c *StatsConnection) GetSystemStats() (*api.SystemStats, error) {
111 stats, err := c.statsClient.DumpStats(SystemStatsPrefix)
116 sysStats := &api.SystemStats{}
118 for _, stat := range stats {
120 case SystemStats_VectorRate:
121 sysStats.VectorRate = scalarStatToFloat64(stat.Data)
122 case SystemStats_InputRate:
123 sysStats.InputRate = scalarStatToFloat64(stat.Data)
124 case SystemStats_LastUpdate:
125 sysStats.LastUpdate = scalarStatToFloat64(stat.Data)
126 case SystemStats_LastStatsClear:
127 sysStats.LastStatsClear = scalarStatToFloat64(stat.Data)
128 case SystemStats_Heartbeat:
129 sysStats.Heartbeat = scalarStatToFloat64(stat.Data)
136 // GetErrorStats retrieves VPP error stats.
137 func (c *StatsConnection) GetErrorStats(names ...string) (*api.ErrorStats, error) {
138 var patterns []string
140 patterns = make([]string, len(names))
141 for i, name := range names {
142 patterns[i] = CounterStatsPrefix + name
145 // retrieve all error counters by default
146 patterns = []string{CounterStatsPrefix}
148 stats, err := c.statsClient.DumpStats(patterns...)
153 var errorStats = &api.ErrorStats{}
155 for _, stat := range stats {
156 statName := strings.TrimPrefix(stat.Name, CounterStatsPrefix)
158 /* TODO: deal with stats that contain '/' in node/counter name
159 parts := strings.Split(statName, "/")
160 var nodeName, counterName string
164 counterName = parts[1]
166 nodeName = parts[0] + parts[1]
167 counterName = parts[2]
170 errorStats.Errors = append(errorStats.Errors, api.ErrorCounter{
171 CounterName: statName,
172 Value: errorStatToUint64(stat.Data),
176 return errorStats, nil
179 // GetNodeStats retrieves VPP per node stats.
180 func (c *StatsConnection) GetNodeStats() (*api.NodeStats, error) {
181 stats, err := c.statsClient.DumpStats(NodeStatsPrefix)
186 nodeStats := &api.NodeStats{}
187 var setPerNode = func(perNode []uint64, fn func(c *api.NodeCounters, v uint64)) {
188 if nodeStats.Nodes == nil {
189 nodeStats.Nodes = make([]api.NodeCounters, len(perNode))
190 for i := range perNode {
191 nodeStats.Nodes[i].NodeIndex = uint32(i)
194 for i, v := range perNode {
195 nodeCounters := nodeStats.Nodes[i]
197 nodeStats.Nodes[i] = nodeCounters
201 for _, stat := range stats {
203 case NodeStats_Clocks:
204 setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
207 case NodeStats_Vectors:
208 setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
211 case NodeStats_Calls:
212 setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
215 case NodeStats_Suspends:
216 setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
222 return nodeStats, nil
225 // GetInterfaceStats retrieves VPP per interface stats.
226 func (c *StatsConnection) GetInterfaceStats() (*api.InterfaceStats, error) {
227 stats, err := c.statsClient.DumpStats(InterfaceStatsPrefix)
232 ifStats := &api.InterfaceStats{}
233 var setPerIf = func(perIf []uint64, fn func(c *api.InterfaceCounters, v uint64)) {
234 if ifStats.Interfaces == nil {
235 ifStats.Interfaces = make([]api.InterfaceCounters, len(perIf))
236 for i := range perIf {
237 ifStats.Interfaces[i].InterfaceIndex = uint32(i)
240 for i, v := range perIf {
241 ifCounters := ifStats.Interfaces[i]
243 ifStats.Interfaces[i] = ifCounters
247 for _, stat := range stats {
249 case InterfaceStats_Drops:
250 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
253 case InterfaceStats_Punt:
254 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
257 case InterfaceStats_IP4:
258 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
261 case InterfaceStats_IP6:
262 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
265 case InterfaceStats_RxNoBuf:
266 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
269 case InterfaceStats_RxMiss:
270 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
273 case InterfaceStats_RxError:
274 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
277 case InterfaceStats_TxError:
278 setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
281 case InterfaceStats_Rx:
282 per := reduceCombinedCounterStat(stat.Data)
283 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
286 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
289 case InterfaceStats_RxUnicast:
290 per := reduceCombinedCounterStat(stat.Data)
291 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
294 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
297 case InterfaceStats_RxMulticast:
298 per := reduceCombinedCounterStat(stat.Data)
299 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
302 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
305 case InterfaceStats_RxBroadcast:
306 per := reduceCombinedCounterStat(stat.Data)
307 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
310 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
313 case InterfaceStats_Tx:
314 per := reduceCombinedCounterStat(stat.Data)
315 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
318 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
321 case InterfaceStats_TxUnicastMiss:
322 per := reduceCombinedCounterStat(stat.Data)
323 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
324 c.TxUnicastMiss[0] = v
326 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
327 c.TxUnicastMiss[1] = v
329 case InterfaceStats_TxMulticast:
330 per := reduceCombinedCounterStat(stat.Data)
331 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
334 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
337 case InterfaceStats_TxBroadcast:
338 per := reduceCombinedCounterStat(stat.Data)
339 setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
342 setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
351 func scalarStatToFloat64(stat adapter.Stat) float64 {
352 if s, ok := stat.(adapter.ScalarStat); ok {
358 func errorStatToUint64(stat adapter.Stat) uint64 {
359 if s, ok := stat.(adapter.ErrorStat); ok {
365 func reduceSimpleCounterStat(stat adapter.Stat) []uint64 {
366 if s, ok := stat.(adapter.SimpleCounterStat); ok {
370 var per = make([]uint64, len(s[0]))
371 for _, w := range s {
372 for i, n := range w {
381 func reduceCombinedCounterStat(stat adapter.Stat) [2][]uint64 {
382 if s, ok := stat.(adapter.CombinedCounterStat); ok {
384 return [2][]uint64{{}, {}}
386 var perPackets = make([]uint64, len(s[0]))
387 var perBytes = make([]uint64, len(s[0]))
388 for _, w := range s {
389 for i, n := range w {
390 perPackets[i] += uint64(n.Packets)
391 perBytes[i] += uint64(n.Bytes)
394 return [2][]uint64{perPackets, perBytes}