Add support for names vector and fill name in interface/node stats 09/18809/1
authorOndrej Fabry <ofabry@cisco.com>
Thu, 11 Apr 2019 08:59:49 +0000 (10:59 +0200)
committerOndrej Fabry <ofabry@cisco.com>
Thu, 11 Apr 2019 08:59:49 +0000 (10:59 +0200)
Change-Id: I3a6bcb635701c0f00e47d04fce2113e1ac23b67b
Signed-off-by: Ondrej Fabry <ofabry@cisco.com>
adapter/stats_api.go
adapter/vppapiclient/stat_client.go
api/stats.go
core/stats.go
examples/stats-api/stats_api.go

index 3538176..4087865 100644 (file)
@@ -39,10 +39,11 @@ type StatType int
 
 const (
        _                     StatType = 0
-       ScalarIndex                    = 1
-       SimpleCounterVector            = 2
-       CombinedCounterVector          = 3
-       ErrorIndex                     = 4
+       ScalarIndex           StatType = 1
+       SimpleCounterVector   StatType = 2
+       CombinedCounterVector StatType = 3
+       ErrorIndex            StatType = 4
+       NameVector            StatType = 5
 )
 
 func (d StatType) String() string {
@@ -55,6 +56,8 @@ func (d StatType) String() string {
                return "CombinedCounterVector"
        case ErrorIndex:
                return "ErrorIndex"
+       case NameVector:
+               return "NameVector"
        }
        return fmt.Sprintf("UnknownStatType(%d)", d)
 }
@@ -76,6 +79,9 @@ type CombinedCounter struct {
        Bytes   Counter
 }
 
+// Name represents string value stored under name vector.
+type Name string
+
 // ScalarStat represents stat for ScalarIndex.
 type ScalarStat float64
 
@@ -92,6 +98,9 @@ type SimpleCounterStat [][]Counter
 // Values should be aggregated per interface/node for every worker.
 type CombinedCounterStat [][]CombinedCounter
 
+// NameStat represents stat for NameVector.
+type NameStat []Name
+
 // Data represents some type of stat which is usually defined by StatType.
 type Stat interface {
        // isStat is unexported to limit implementations of Data interface to this package,
@@ -102,3 +111,4 @@ func (ScalarStat) isStat()          {}
 func (ErrorStat) isStat()           {}
 func (SimpleCounterStat) isStat()   {}
 func (CombinedCounterStat) isStat() {}
+func (NameStat) isStat()            {}
index df192f6..a2a9826 100644 (file)
@@ -40,7 +40,7 @@ govpp_stat_disconnect()
 }
 
 static uint32_t*
-govpp_stat_segment_ls(uint8_t ** pattern)
+govpp_stat_segment_ls(uint8_t **pattern)
 {
        return stat_segment_ls(pattern);
 }
@@ -135,6 +135,18 @@ govpp_stat_segment_data_get_combined_counter_index_bytes(stat_segment_data_t *da
        return data->combined_counter_vec[index][index2].bytes;
 }
 
+static uint8_t**
+govpp_stat_segment_data_get_name_vector(stat_segment_data_t *data)
+{
+       return data->name_vector;
+}
+
+static char*
+govpp_stat_segment_data_get_name_vector_index(stat_segment_data_t *data, int index)
+{
+       return data->name_vector[index];
+}
+
 static void
 govpp_stat_segment_data_free(stat_segment_data_t *data)
 {
@@ -268,8 +280,20 @@ func (c *statClient) DumpStats(patterns ...string) (stats []*adapter.StatEntry,
                        }
                        stat.Data = adapter.CombinedCounterStat(vector)
 
+               case adapter.NameVector:
+                       length := int(C.govpp_stat_segment_vec_len(unsafe.Pointer(C.govpp_stat_segment_data_get_name_vector(&v))))
+                       var vector []adapter.Name
+                       for k := 0; k < length; k++ {
+                               s := C.govpp_stat_segment_data_get_name_vector_index(&v, C.int(k))
+                               if s == nil {
+                                       continue
+                               }
+                               vector = append(vector, adapter.Name(C.GoString(s)))
+                       }
+                       stat.Data = adapter.NameStat(vector)
+
                default:
-                       fmt.Fprintf(os.Stderr, "invalid stat type: %v (%d)", typ, typ)
+                       fmt.Fprintf(os.Stderr, "invalid stat type: %v (%v)\n", typ, name)
                        continue
 
                }
index ec623c7..9c3a16f 100644 (file)
@@ -17,8 +17,7 @@ type NodeStats struct {
 // NodeCounters represents node counters.
 type NodeCounters struct {
        NodeIndex uint32
-       // TODO: node name is not currently retrievable via stats API (will be most likely added in 19.04)
-       //NodeName string
+       NodeName  string // requires VPP 19.04+
 
        Clocks   uint64
        Vectors  uint64
@@ -34,8 +33,7 @@ type InterfaceStats struct {
 // InterfaceCounters represents interface counters.
 type InterfaceCounters struct {
        InterfaceIndex uint32
-       // TODO: interface name is not currently retrievable via stats API (will be most likely added in 19.04)
-       //InterfaceName string
+       InterfaceName  string // requires VPP 19.04+
 
        RxPackets uint64
        RxBytes   uint64
index 26b9bc9..4cbd9f2 100644 (file)
@@ -1,6 +1,7 @@
 package core
 
 import (
+       "fmt"
        "strings"
        "sync/atomic"
 
@@ -19,12 +20,14 @@ const (
        SystemStats_Heartbeat      = SystemStatsPrefix + "heartbeat"
 
        NodeStatsPrefix    = "/sys/node/"
+       NodeStats_Names    = NodeStatsPrefix + "names"
        NodeStats_Clocks   = NodeStatsPrefix + "clocks"
        NodeStats_Vectors  = NodeStatsPrefix + "vectors"
        NodeStats_Calls    = NodeStatsPrefix + "calls"
        NodeStats_Suspends = NodeStatsPrefix + "suspends"
 
        InterfaceStatsPrefix         = "/if/"
+       InterfaceStats_Names         = InterfaceStatsPrefix + "names"
        InterfaceStats_Drops         = InterfaceStatsPrefix + "drops"
        InterfaceStats_Punt          = InterfaceStatsPrefix + "punt"
        InterfaceStats_IP4           = InterfaceStatsPrefix + "ip4"
@@ -42,7 +45,8 @@ const (
        InterfaceStats_TxMulticast   = InterfaceStatsPrefix + "tx-multicast"
        InterfaceStats_TxBroadcast   = InterfaceStatsPrefix + "tx-broadcast"
 
-       NetworkStatsPrefix     = "/net/"
+       NetworkStatsPrefix = "/net/"
+       // TODO: network stats
        NetworkStats_RouteTo   = NetworkStatsPrefix + "route/to"
        NetworkStats_RouteVia  = NetworkStatsPrefix + "route/via"
        NetworkStats_MRoute    = NetworkStatsPrefix + "mroute"
@@ -200,6 +204,20 @@ func (c *StatsConnection) GetNodeStats() (*api.NodeStats, error) {
 
        for _, stat := range stats {
                switch stat.Name {
+               case NodeStats_Names:
+                       if names, ok := stat.Data.(adapter.NameStat); !ok {
+                               return nil, fmt.Errorf("invalid stat type for %s", stat.Name)
+                       } else {
+                               if nodeStats.Nodes == nil {
+                                       nodeStats.Nodes = make([]api.NodeCounters, len(names))
+                                       for i := range names {
+                                               nodeStats.Nodes[i].NodeIndex = uint32(i)
+                                       }
+                               }
+                               for i, name := range names {
+                                       nodeStats.Nodes[i].NodeName = string(name)
+                               }
+                       }
                case NodeStats_Clocks:
                        setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
                                c.Clocks = v
@@ -230,6 +248,7 @@ func (c *StatsConnection) GetInterfaceStats() (*api.InterfaceStats, error) {
        }
 
        ifStats := &api.InterfaceStats{}
+
        var setPerIf = func(perIf []uint64, fn func(c *api.InterfaceCounters, v uint64)) {
                if ifStats.Interfaces == nil {
                        ifStats.Interfaces = make([]api.InterfaceCounters, len(perIf))
@@ -246,6 +265,20 @@ func (c *StatsConnection) GetInterfaceStats() (*api.InterfaceStats, error) {
 
        for _, stat := range stats {
                switch stat.Name {
+               case InterfaceStats_Names:
+                       if names, ok := stat.Data.(adapter.NameStat); !ok {
+                               return nil, fmt.Errorf("invalid stat type for %s", stat.Name)
+                       } else {
+                               if ifStats.Interfaces == nil {
+                                       ifStats.Interfaces = make([]api.InterfaceCounters, len(names))
+                                       for i := range names {
+                                               ifStats.Interfaces[i].InterfaceIndex = uint32(i)
+                                       }
+                               }
+                               for i, name := range names {
+                                       ifStats.Interfaces[i].InterfaceName = string(name)
+                               }
+                       }
                case InterfaceStats_Drops:
                        setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
                                c.Drops = v
index b905f60..9808243 100644 (file)
@@ -170,6 +170,7 @@ func isZero(stat adapter.Stat) bool {
                                }
                        }
                }
+               return true
        case adapter.CombinedCounterStat:
                for _, ss := range s {
                        for _, sss := range ss {
@@ -178,6 +179,7 @@ func isZero(stat adapter.Stat) bool {
                                }
                        }
                }
+               return true
        }
-       return true
+       return false
 }