Refactor GoVPP
[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         "os"
22         "os/signal"
23
24         "git.fd.io/govpp.git"
25         "git.fd.io/govpp.git/api"
26         "git.fd.io/govpp.git/core"
27         "git.fd.io/govpp.git/examples/bin_api/stats"
28 )
29
30 func main() {
31         fmt.Println("Starting stats VPP client...")
32
33         // async connect to VPP
34         conn, statCh, err := govpp.AsyncConnect("")
35         if err != nil {
36                 fmt.Println("Error:", err)
37                 os.Exit(1)
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                 fmt.Println("Error:", err)
45                 os.Exit(1)
46         }
47         defer fmt.Println("calling close")
48         defer ch.Close()
49
50         // create channel for Interrupt signal
51         sigChan := make(chan os.Signal, 1)
52         signal.Notify(sigChan, os.Interrupt)
53
54         var simpleCountersSubs *api.NotifSubscription
55         var combinedCountersSubs *api.NotifSubscription
56         var notifChan chan api.Message
57
58         // loop until Interrupt signal is received
59 loop:
60         for {
61                 select {
62
63                 case connEvent := <-statCh:
64                         // VPP connection state change
65                         switch connEvent.State {
66                         case core.Connected:
67                                 fmt.Println("VPP connected.")
68                                 if simpleCountersSubs == nil {
69                                         simpleCountersSubs, combinedCountersSubs, notifChan = subscribeNotifications(ch)
70                                 }
71                                 requestStatistics(ch)
72
73                         case core.Disconnected:
74                                 fmt.Println("VPP disconnected.")
75                         }
76
77                 case msg := <-notifChan:
78                         switch notif := msg.(type) {
79                         case *stats.VnetInterfaceSimpleCounters:
80                                 // simple counter notification received
81                                 processSimpleCounters(notif)
82                         case *stats.VnetInterfaceCombinedCounters:
83                                 // combined counter notification received
84                                 processCombinedCounters(notif)
85                         default:
86                                 fmt.Println("Ignoring unknown VPP notification")
87                         }
88
89                 case <-sigChan:
90                         // interrupt received
91                         fmt.Println("Interrupt received, exiting.")
92                         break loop
93                 }
94         }
95
96         ch.UnsubscribeNotification(simpleCountersSubs)
97         ch.UnsubscribeNotification(combinedCountersSubs)
98 }
99
100 // subscribeNotifications subscribes for interface counters notifications.
101 func subscribeNotifications(ch api.Channel) (*api.NotifSubscription, *api.NotifSubscription, chan api.Message) {
102         notifChan := make(chan api.Message, 100)
103
104         simpleCountersSubs, err := ch.SubscribeNotification(notifChan, stats.NewVnetInterfaceSimpleCounters)
105         if err != nil {
106                 panic(err)
107         }
108         combinedCountersSubs, err := ch.SubscribeNotification(notifChan, stats.NewVnetInterfaceCombinedCounters)
109         if err != nil {
110                 panic(err)
111         }
112
113         return simpleCountersSubs, combinedCountersSubs, notifChan
114 }
115
116 // requestStatistics requests interface counters notifications from VPP.
117 func requestStatistics(ch api.Channel) {
118         if err := ch.SendRequest(&stats.WantStats{
119                 PID:           uint32(os.Getpid()),
120                 EnableDisable: 1,
121         }).ReceiveReply(&stats.WantStatsReply{}); err != nil {
122                 panic(err)
123         }
124 }
125
126 // processSimpleCounters processes simple counters received from VPP.
127 func processSimpleCounters(counters *stats.VnetInterfaceSimpleCounters) {
128         fmt.Printf("SimpleCounters: %+v\n", counters)
129
130         counterNames := []string{
131                 "Drop", "Punt",
132                 "IPv4", "IPv6",
133                 "RxNoBuf", "RxMiss",
134                 "RxError", "TxError",
135                 "MPLS",
136         }
137
138         for i := uint32(0); i < counters.Count; i++ {
139                 fmt.Printf("Interface '%d': %s = %d\n",
140                         counters.FirstSwIfIndex+i, counterNames[counters.VnetCounterType], counters.Data[i])
141         }
142 }
143
144 // processCombinedCounters processes combined counters received from VPP.
145 func processCombinedCounters(counters *stats.VnetInterfaceCombinedCounters) {
146         fmt.Printf("CombinedCounters: %+v\n", counters)
147
148         counterNames := []string{"Rx", "Tx"}
149
150         for i := uint32(0); i < counters.Count; i++ {
151                 if len(counterNames) <= int(counters.VnetCounterType) {
152                         continue
153                 }
154                 fmt.Printf("Interface '%d': %s packets = %d, %s bytes = %d\n",
155                         counters.FirstSwIfIndex+i,
156                         counterNames[counters.VnetCounterType], counters.Data[i].Packets,
157                         counterNames[counters.VnetCounterType], counters.Data[i].Bytes)
158         }
159 }