docs: fix memory traces command
[vpp.git] / extras / gomemif / examples / icmp_responder_cb.go
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2020 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 package main
19
20 import (
21         "bufio"
22         "flag"
23         "fmt"
24         "net"
25         "os"
26         "strings"
27         "sync"
28
29         "memif"
30
31         "github.com/google/gopacket"
32         "github.com/google/gopacket/layers"
33         "github.com/pkg/profile"
34 )
35
36 func Disconnected(i *memif.Interface) error {
37         fmt.Println("Disconnected: ", i.GetName())
38
39         data, ok := i.GetPrivateData().(*interfaceData)
40         if !ok {
41                 return fmt.Errorf("Invalid private data")
42         }
43         close(data.quitChan) // stop polling
44         close(data.errChan)
45         data.wg.Wait() // wait until polling stops, then continue disconnect
46
47         return nil
48 }
49
50 func Responder(i *memif.Interface) error {
51         data, ok := i.GetPrivateData().(*interfaceData)
52         if !ok {
53                 return fmt.Errorf("Invalid private data")
54         }
55         data.errChan = make(chan error, 1)
56         data.quitChan = make(chan struct{}, 1)
57         data.wg.Add(1)
58
59         // allocate packet buffer
60         pkt := make([]byte, 2048)
61         // get rx queue
62         rxq0, err := i.GetRxQueue(0)
63         if err != nil {
64                 return err
65         }
66         // get tx queue
67         txq0, err := i.GetTxQueue(0)
68         if err != nil {
69                 return err
70         }
71         for {
72
73                 // read packet from shared memory
74                 pktLen, err := rxq0.ReadPacket(pkt)
75                 _ = err
76                 if pktLen > 0 {
77                         fmt.Printf("pktLen: %d\n", pktLen)
78                         gopkt := gopacket.NewPacket(pkt[:pktLen], layers.LayerTypeEthernet, gopacket.NoCopy)
79                         etherLayer := gopkt.Layer(layers.LayerTypeEthernet)
80                         if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeARP {
81                                 rEth := layers.Ethernet{
82                                         SrcMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
83                                         DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
84
85                                         EthernetType: layers.EthernetTypeARP,
86                                 }
87                                 rArp := layers.ARP{
88                                         AddrType:          layers.LinkTypeEthernet,
89                                         Protocol:          layers.EthernetTypeIPv4,
90                                         HwAddressSize:     6,
91                                         ProtAddressSize:   4,
92                                         Operation:         layers.ARPReply,
93                                         SourceHwAddress:   []byte(net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}),
94                                         SourceProtAddress: []byte("\xc0\xa8\x01\x01"),
95                                         DstHwAddress:      []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
96                                         DstProtAddress:    []byte("\xc0\xa8\x01\x02"),
97                                 }
98                                 buf := gopacket.NewSerializeBuffer()
99                                 opts := gopacket.SerializeOptions{
100                                         FixLengths:       true,
101                                         ComputeChecksums: true,
102                                 }
103                                 gopacket.SerializeLayers(buf, opts, &rEth, &rArp)
104                                 // write packet to shared memory
105                                 txq0.WritePacket(buf.Bytes())
106                         }
107
108                         if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeIPv4 {
109                                 ipLayer := gopkt.Layer(layers.LayerTypeIPv4)
110                                 if ipLayer == nil {
111                                         fmt.Println("Missing IPv4 layer.")
112
113                                 }
114                                 ipv4, _ := ipLayer.(*layers.IPv4)
115                                 if ipv4.Protocol != layers.IPProtocolICMPv4 {
116                                         fmt.Println("Not ICMPv4 protocol.")
117                                 }
118                                 icmpLayer := gopkt.Layer(layers.LayerTypeICMPv4)
119                                 if icmpLayer == nil {
120                                         fmt.Println("Missing ICMPv4 layer.")
121                                 }
122                                 icmp, _ := icmpLayer.(*layers.ICMPv4)
123                                 if icmp.TypeCode.Type() != layers.ICMPv4TypeEchoRequest {
124                                         fmt.Println("Not ICMPv4 echo request.")
125                                 }
126                                 fmt.Println("Received an ICMPv4 echo request.")
127
128                                 // Build packet layers.
129                                 ethResp := layers.Ethernet{
130                                         DstMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
131                                         //DstMAC: net.HardwareAddr{0x02, 0xfe, 0xa8, 0x77, 0xaf, 0x20},
132                                         SrcMAC: []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
133
134                                         EthernetType: layers.EthernetTypeIPv4,
135                                 }
136                                 ipv4Resp := layers.IPv4{
137                                         Version:    4,
138                                         IHL:        5,
139                                         TOS:        0,
140                                         Id:         0,
141                                         Flags:      0,
142                                         FragOffset: 0,
143                                         TTL:        255,
144                                         Protocol:   layers.IPProtocolICMPv4,
145                                         SrcIP:      []byte("\xc0\xa8\x01\x01"),
146                                         DstIP:      []byte("\xc0\xa8\x01\x02"),
147                                 }
148                                 icmpResp := layers.ICMPv4{
149                                         TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoReply, 0),
150                                         Id:       icmp.Id,
151                                         Seq:      icmp.Seq,
152                                 }
153
154                                 // Set up buffer and options for serialization.
155                                 buf := gopacket.NewSerializeBuffer()
156                                 opts := gopacket.SerializeOptions{
157                                         FixLengths:       true,
158                                         ComputeChecksums: true,
159                                 }
160                                 gopacket.SerializeLayers(buf, opts, &ethResp, &ipv4Resp, &icmpResp,
161                                         gopacket.Payload(icmp.Payload))
162                                 // write packet to shared memory
163                                 txq0.WritePacket(buf.Bytes())
164                         }
165
166                 }
167                 return nil
168
169         }
170
171 }
172 func Connected(i *memif.Interface) error {
173         data, ok := i.GetPrivateData().(*interfaceData)
174         if !ok {
175                 return fmt.Errorf("Invalid private data")
176         }
177         _ = data
178
179         // allocate packet buffer
180         pkt := make([]byte, 2048)
181         // get rx queue
182         rxq0, err := i.GetRxQueue(0)
183         _ = err
184
185         // read packet from shared memory
186         pktLen, err := rxq0.ReadPacket(pkt)
187         _, _ = err, pktLen
188
189         return nil
190 }
191
192 type interfaceData struct {
193         errChan  chan error
194         quitChan chan struct{}
195         wg       sync.WaitGroup
196 }
197
198 func interractiveHelp() {
199         fmt.Println("help - print this help")
200         fmt.Println("start - start connecting loop")
201         fmt.Println("show - print interface details")
202         fmt.Println("exit - exit the application")
203 }
204
205 func main() {
206         cpuprof := flag.String("cpuprof", "", "cpu profiling output file")
207         memprof := flag.String("memprof", "", "mem profiling output file")
208         role := flag.String("role", "slave", "interface role")
209         name := flag.String("name", "gomemif", "interface name")
210         socketName := flag.String("socket", "/run/vpp/memif.sock", "control socket filename")
211
212         flag.Parse()
213
214         if *cpuprof != "" {
215                 defer profile.Start(profile.CPUProfile, profile.ProfilePath(*cpuprof)).Stop()
216         }
217         if *memprof != "" {
218                 defer profile.Start(profile.MemProfile, profile.ProfilePath(*memprof)).Stop()
219         }
220
221         memifErrChan := make(chan error)
222         exitChan := make(chan struct{})
223
224         var isMaster bool
225         switch *role {
226         case "slave":
227                 isMaster = false
228         case "master":
229                 isMaster = true
230         default:
231                 fmt.Println("Invalid role")
232                 return
233         }
234
235         fmt.Println("GoMemif: Responder")
236         fmt.Println("-----------------------")
237
238         socket, err := memif.NewSocket("gomemif_example", *socketName)
239         if err != nil {
240                 fmt.Println("Failed to create socket: ", err)
241                 return
242         }
243
244         data := interfaceData{}
245         args := &memif.Arguments{
246                 IsMaster:         isMaster,
247                 ConnectedFunc:    Connected,
248                 DisconnectedFunc: Disconnected,
249                 PrivateData:      &data,
250                 Name:             *name,
251                 InterruptFunc:    Responder,
252         }
253
254         i, err := socket.NewInterface(args)
255         if err != nil {
256                 fmt.Println("Failed to create interface on socket %s: %s", socket.GetFilename(), err)
257                 goto exit
258         }
259
260         // slave attempts to connect to control socket
261         // to handle control communication call socket.StartPolling()
262         if !i.IsMaster() {
263                 fmt.Println(args.Name, ": Connecting to control socket...")
264                 for !i.IsConnecting() {
265                         err = i.RequestConnection()
266                         if err != nil {
267                                 /* TODO: check for ECONNREFUSED errno
268                                  * if error is ECONNREFUSED it may simply mean that master
269                                  * interface is not up yet, use i.RequestConnection()
270                                  */
271                                 fmt.Println("Failed to connect: ", err)
272                                 goto exit
273                         }
274                 }
275         }
276
277         go func(exitChan chan<- struct{}) {
278                 reader := bufio.NewReader(os.Stdin)
279                 for {
280                         fmt.Print("gomemif# ")
281                         text, _ := reader.ReadString('\n')
282                         // convert CRLF to LF
283                         text = strings.Replace(text, "\n", "", -1)
284                         switch text {
285                         case "help":
286                                 interractiveHelp()
287                         case "start":
288                                 // start polling for events on this socket
289                                 socket.StartPolling(memifErrChan)
290                         case "show":
291                                 fmt.Println("remote: ", i.GetRemoteName())
292                                 fmt.Println("peer: ", i.GetPeerName())
293                         case "exit":
294                                 err = socket.StopPolling()
295                                 if err != nil {
296                                         fmt.Println("Failed to stop polling: ", err)
297                                 }
298                                 close(exitChan)
299                                 return
300                         default:
301                                 fmt.Println("Unknown input")
302                         }
303                 }
304         }(exitChan)
305
306         for {
307                 select {
308                 case <-exitChan:
309                         goto exit
310                 case err, ok := <-memifErrChan:
311                         if ok {
312                                 fmt.Println(err)
313                         }
314                 case err, ok := <-data.errChan:
315                         if ok {
316                                 fmt.Println(err)
317                         }
318                 default:
319                         continue
320                 }
321         }
322
323 exit:
324         socket.Delete()
325         close(memifErrChan)
326 }