blob: 751bbe5d5a964f065220d5a5e5571f6f7d42d6f5 [file] [log] [blame]
Koren Lev19ca78f2018-11-21 18:46:54 +02001package main
2
3import (
4 "flag"
5 "fmt"
Adrian Villin5a4c7a92024-09-26 11:24:34 +02006 "log"
7
Koren Lev19ca78f2018-11-21 18:46:54 +02008 "git.fd.io/govpp.git"
9 "git.fd.io/govpp.git/adapter"
10 "git.fd.io/govpp.git/adapter/vppapiclient"
11 "git.fd.io/govpp.git/api"
12 "git.fd.io/govpp.git/core"
13 "git.fd.io/govpp.git/examples/bin_api/interfaces"
14 "git.fd.io/govpp.git/examples/bin_api/vpe"
Koren Lev19ca78f2018-11-21 18:46:54 +020015)
16
17//////////////////////////////////////
18///////// Data structs ///////////
19//////////////////////////////////////
20
21const defaultStatsSocketPath = "/run/vpp/stats.sock"
22const defaultShmPrefix = ""
23
24func parseMacAddress(l2Address []byte, l2AddressLength uint32) string {
25 var mac string
26 for i := uint32(0); i < l2AddressLength; i++ {
27 mac += fmt.Sprintf("%02x", l2Address[i])
28 if i < l2AddressLength-1 {
29 mac += ":"
30 }
31 }
32 return mac
33}
34
35type interfaceStats struct {
36 TxBytes uint64
37 TxPackets uint64
38 TxErrors uint64
39 RxBytes uint64
40 RxPackets uint64
41 RxErrors uint64
42 Drops uint64
43 Punts uint64
44}
45
46type vppInterface struct {
47 interfaces.SwInterfaceDetails
48 Stats interfaceStats
49}
50
51type vppConnector struct {
52 statsSocketPath string
53 shmPrefix string
54
55 conn *core.Connection
56 api api.Channel
57 stats adapter.StatsAPI
58
59 VppDetails vpe.ShowVersionReply
60 Interfaces []*vppInterface
61}
62
63//////////////////////////////////////
64///////// VPP workflow ///////////
65//////////////////////////////////////
66
67func (v *vppConnector) getVppVersion() error {
68 if err := v.api.SendRequest(&vpe.ShowVersion{}).ReceiveReply(&v.VppDetails); err != nil {
69 return fmt.Errorf("failed to fetch vpp version: %v", err)
70 }
71 return nil
72}
73
74func (v *vppConnector) getInterfaces() error {
75 ifCtx := v.api.SendMultiRequest(&interfaces.SwInterfaceDump{})
76 for {
77 ifDetails := interfaces.SwInterfaceDetails{}
78 stop, err := ifCtx.ReceiveReply(&ifDetails)
79 if err != nil {
80 return fmt.Errorf("failed to fetch vpp interface: %v", err)
81 }
82 if stop {
83 break
84 }
85
86 v.Interfaces = append(v.Interfaces, &vppInterface{SwInterfaceDetails: ifDetails})
87 }
88 return nil
89}
90
91func (v *vppConnector) connect() (err error) {
92 if v.conn, err = govpp.Connect(v.shmPrefix); err != nil {
93 return fmt.Errorf("failed to connect to vpp: %v", err)
94 }
95
96 if v.api, err = v.conn.NewAPIChannel(); err != nil {
97 return fmt.Errorf("failed to create api channel: %v", err)
98 }
99
100 v.stats = vppapiclient.NewStatClient(v.statsSocketPath)
101 if err = v.stats.Connect(); err != nil {
102 return fmt.Errorf("failed to connect to Stats adapter: %v", err)
103 }
104
105 return
106}
107
108func (v *vppConnector) disconnect() {
109 if v.stats != nil {
110 v.stats.Disconnect()
111 }
112 if v.conn != nil {
113 v.conn.Disconnect()
114 }
115}
116
117func (v *vppConnector) reduceCombinedCounters(stat *adapter.StatEntry) *[]adapter.CombinedCounter {
118 counters := stat.Data.(adapter.CombinedCounterStat)
119 stats := make([]adapter.CombinedCounter, len(v.Interfaces))
120 for _, workerStats := range counters {
Koren Levf3b7a5e2018-12-06 10:51:18 +0200121 for i := 0; i < len(v.Interfaces); i++ {
122 stats[i].Bytes += workerStats[i].Bytes
123 stats[i].Packets += workerStats[i].Packets
Koren Lev19ca78f2018-11-21 18:46:54 +0200124 }
125 }
126 return &stats
127}
128
129func (v *vppConnector) reduceSimpleCounters(stat *adapter.StatEntry) *[]adapter.Counter {
130 counters := stat.Data.(adapter.SimpleCounterStat)
131 stats := make([]adapter.Counter, len(v.Interfaces))
132 for _, workerStats := range counters {
Koren Levf3b7a5e2018-12-06 10:51:18 +0200133 for i := 0; i < len(v.Interfaces); i++ {
134 stats[i] += workerStats[i]
Koren Lev19ca78f2018-11-21 18:46:54 +0200135 }
136 }
137 return &stats
138}
139
140func (v *vppConnector) getStatsForAllInterfaces() error {
141 statsDump, err := v.stats.DumpStats("/if")
142 if err != nil {
143 return fmt.Errorf("failed to dump vpp Stats: %v", err)
144 }
145
146 stats := func(i int) *interfaceStats { return &v.Interfaces[uint32(i)].Stats }
147
148 for _, stat := range statsDump {
149 switch stat.Name {
150 case "/if/tx":
151 {
152 for i, counter := range *v.reduceCombinedCounters(stat) {
153 stats(i).TxBytes = uint64(counter.Bytes)
154 stats(i).TxPackets = uint64(counter.Packets)
155 }
156 }
157 case "/if/rx":
158 {
159 for i, counter := range *v.reduceCombinedCounters(stat) {
160 stats(i).RxBytes = uint64(counter.Bytes)
161 stats(i).RxPackets = uint64(counter.Packets)
162 }
163 }
164 case "/if/tx-error":
165 {
166 for i, counter := range *v.reduceSimpleCounters(stat) {
167 stats(i).TxErrors = uint64(counter)
168 }
169 }
170 case "/if/rx-error":
171 {
172 for i, counter := range *v.reduceSimpleCounters(stat) {
173 stats(i).RxErrors = uint64(counter)
174 }
175 }
176 case "/if/drops":
177 {
178 for i, counter := range *v.reduceSimpleCounters(stat) {
179 stats(i).Drops = uint64(counter)
180 }
181 }
182 case "/if/punt":
183 {
184 for i, counter := range *v.reduceSimpleCounters(stat) {
185 stats(i).Punts = uint64(counter)
186 }
187 }
188 }
189 }
190 return nil
191}
192
193//////////////////////////////////////
194
195func main() {
196 statsSocketPathPtr := flag.String("stats_socket_path", defaultStatsSocketPath, "Path to vpp stats socket")
197 shmPrefixPtr := flag.String("shm_prefix", defaultShmPrefix, "Shared memory prefix (advanced)")
198 flag.Parse()
199
200 vppConn := &vppConnector{statsSocketPath: *statsSocketPathPtr, shmPrefix: *shmPrefixPtr}
201 defer vppConn.disconnect()
202
203 if err := vppConn.connect(); err != nil {
204 log.Fatalln(err)
205 }
206
207 if err := vppConn.getVppVersion(); err != nil {
208 log.Fatalln(err)
209 }
210
211 if err := vppConn.getInterfaces(); err != nil {
212 log.Fatalln(err)
213 }
214
215 if err := vppConn.getStatsForAllInterfaces(); err != nil {
216 log.Fatalln(err)
217 }
218
219 jsonString, err := dumpToJSONString(vppConn)
220 if err != nil {
221 log.Fatalln(err)
222 }
223 fmt.Println(jsonString)
224}