f61f9755b4c6746a68aeb1c773f54d8831aab963
[govpp.git] / examples / cmd / stats-client / stats_client.go
1 // Copyright (c) 2017 Cisco and/or its affiliates.
2 //
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:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 // Binary stats-client is an example VPP management application that exercises the
16 // govpp API for interface counters together with asynchronous connection to VPP.
17 package main
18
19 import (
20         "fmt"
21         "log"
22         "os"
23         "os/signal"
24
25         "git.fd.io/govpp.git"
26         "git.fd.io/govpp.git/api"
27         "git.fd.io/govpp.git/core"
28         "git.fd.io/govpp.git/examples/bin_api/stats"
29 )
30
31 func main() {
32         fmt.Println("Starting stats VPP client..")
33
34         // async connect to VPP
35         conn, statCh, err := govpp.AsyncConnect("")
36         if err != nil {
37                 log.Fatalln("Error:", err)
38         }
39         defer conn.Disconnect()
40
41         // create an API channel that will be used in the examples
42         ch, err := conn.NewAPIChannel()
43         if err != nil {
44                 log.Fatalln("Error:", err)
45         }
46         defer ch.Close()
47
48         // create channel for Interrupt signal
49         sigChan := make(chan os.Signal, 1)
50         signal.Notify(sigChan, os.Interrupt)
51
52         var notifChan chan api.Message
53         var simpleSub api.SubscriptionCtx
54         var combinedSub api.SubscriptionCtx
55
56         // loop until Interrupt signal is received
57 loop:
58         for {
59                 select {
60                 case connEvent := <-statCh:
61                         // VPP connection state change
62                         switch connEvent.State {
63                         case core.Connected:
64                                 fmt.Println("VPP connected.")
65                                 if notifChan == nil {
66                                         simpleSub, combinedSub, notifChan = subscribeNotifications(ch)
67                                 }
68                                 requestStatistics(ch)
69
70                         case core.Disconnected:
71                                 fmt.Println("VPP disconnected.")
72                         }
73
74                 case msg := <-notifChan:
75                         switch notif := msg.(type) {
76                         case *stats.VnetInterfaceSimpleCounters:
77                                 // simple counter notification received
78                                 processSimpleCounters(notif)
79                         case *stats.VnetInterfaceCombinedCounters:
80                                 // combined counter notification received
81                                 processCombinedCounters(notif)
82                         default:
83                                 fmt.Println("Ignoring unknown VPP notification")
84                         }
85
86                 case <-sigChan:
87                         // interrupt received
88                         fmt.Println("Interrupt received, exiting.")
89                         break loop
90                 }
91         }
92
93         simpleSub.Unsubscribe()
94         combinedSub.Unsubscribe()
95 }
96
97 // subscribeNotifications subscribes for interface counters notifications.
98 func subscribeNotifications(ch api.Channel) (api.SubscriptionCtx, api.SubscriptionCtx, chan api.Message) {
99         notifChan := make(chan api.Message, 100)
100
101         simpleSub, err := ch.SubscribeNotification(notifChan, &stats.VnetInterfaceSimpleCounters{})
102         if err != nil {
103                 panic(err)
104         }
105         combinedSub, err := ch.SubscribeNotification(notifChan, &stats.VnetInterfaceCombinedCounters{})
106         if err != nil {
107                 panic(err)
108         }
109
110         return simpleSub, combinedSub, notifChan
111 }
112
113 // requestStatistics requests interface counters notifications from VPP.
114 func requestStatistics(ch api.Channel) {
115         if err := ch.SendRequest(&stats.WantStats{
116                 PID:           uint32(os.Getpid()),
117                 EnableDisable: 1,
118         }).ReceiveReply(&stats.WantStatsReply{}); err != nil {
119                 panic(err)
120         }
121 }
122
123 // processSimpleCounters processes simple counters received from VPP.
124 func processSimpleCounters(counters *stats.VnetInterfaceSimpleCounters) {
125         fmt.Printf("SimpleCounters: %+v\n", counters)
126
127         counterNames := []string{
128                 "Drop", "Punt",
129                 "IPv4", "IPv6",
130                 "RxNoBuf", "RxMiss",
131                 "RxError", "TxError",
132                 "MPLS",
133         }
134
135         for i := uint32(0); i < counters.Count; i++ {
136                 fmt.Printf("Interface '%d': %s = %d\n",
137                         counters.FirstSwIfIndex+i, counterNames[counters.VnetCounterType], counters.Data[i])
138         }
139 }
140
141 // processCombinedCounters processes combined counters received from VPP.
142 func processCombinedCounters(counters *stats.VnetInterfaceCombinedCounters) {
143         fmt.Printf("CombinedCounters: %+v\n", counters)
144
145         counterNames := []string{"Rx", "Tx"}
146
147         for i := uint32(0); i < counters.Count; i++ {
148                 if len(counterNames) <= int(counters.VnetCounterType) {
149                         continue
150                 }
151                 fmt.Printf("Interface '%d': %s packets = %d, %s bytes = %d\n",
152                         counters.FirstSwIfIndex+i,
153                         counterNames[counters.VnetCounterType], counters.Data[i].Packets,
154                         counterNames[counters.VnetCounterType], counters.Data[i].Bytes)
155         }
156 }