f9f1c3e8208b0243d00e782efd01a6cdd6cc456e
[vpp.git] / extras / gomemif / examples / icmp_responder_poll.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 Connected(i *memif.Interface) error {
51         fmt.Println("Connected: ", i.GetName())
52
53         data, ok := i.GetPrivateData().(*interfaceData)
54         if !ok {
55                 return fmt.Errorf("Invalid private data")
56         }
57         data.errChan = make(chan error, 1)
58         data.quitChan = make(chan struct{}, 1)
59         data.wg.Add(1)
60
61         go func(errChan chan<- error, quitChan <-chan struct{}, wg *sync.WaitGroup) {
62                 defer wg.Done()
63                 // allocate packet buffer
64                 pkt := make([]byte, 2048)
65                 // get rx queue
66                 rxq0, err := i.GetRxQueue(0)
67                 if err != nil {
68                         errChan <- err
69                         return
70                 }
71                 // get tx queue
72                 txq0, err := i.GetTxQueue(0)
73                 if err != nil {
74                         errChan <- err
75                         return
76                 }
77                 for {
78                         select {
79                         case <-quitChan: // channel closed
80                                 return
81                         default:
82                                 // read packet from shared memory
83                                 pktLen, err := rxq0.ReadPacket(pkt)
84                                 if pktLen > 0 {
85                                         fmt.Printf("pktLen: %d\n", pktLen)
86                                         gopkt := gopacket.NewPacket(pkt[:pktLen], layers.LayerTypeEthernet, gopacket.NoCopy)
87                                         etherLayer := gopkt.Layer(layers.LayerTypeEthernet)
88                                         if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeARP {
89
90                                                 rEth := layers.Ethernet{
91                                                         SrcMAC:       net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
92                                                         DstMAC:       net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
93                                                         EthernetType: layers.EthernetTypeARP,
94                                                 }
95                                                 rArp := layers.ARP{
96                                                         AddrType:          layers.LinkTypeEthernet,
97                                                         Protocol:          layers.EthernetTypeIPv4,
98                                                         HwAddressSize:     6,
99                                                         ProtAddressSize:   4,
100                                                         Operation:         layers.ARPReply,
101                                                         SourceHwAddress:   []byte(net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}),
102                                                         SourceProtAddress: []byte("\xc0\xa8\x01\x01"),
103                                                         DstHwAddress:      []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
104                                                         DstProtAddress:    []byte("\xc0\xa8\x01\x02"),
105                                                 }
106                                                 buf := gopacket.NewSerializeBuffer()
107                                                 opts := gopacket.SerializeOptions{
108                                                         FixLengths:       true,
109                                                         ComputeChecksums: true,
110                                                 }
111                                                 gopacket.SerializeLayers(buf, opts, &rEth, &rArp)
112                                                 // write packet to shared memory
113                                                 txq0.WritePacket(buf.Bytes())
114                                         }
115
116                                         if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeIPv4 {
117                                                 ipLayer := gopkt.Layer(layers.LayerTypeIPv4)
118                                                 if ipLayer == nil {
119                                                         fmt.Println("Missing IPv4 layer.")
120
121                                                 }
122                                                 ipv4, _ := ipLayer.(*layers.IPv4)
123                                                 if ipv4.Protocol != layers.IPProtocolICMPv4 {
124                                                         fmt.Println("Not ICMPv4 protocol.")
125                                                 }
126                                                 icmpLayer := gopkt.Layer(layers.LayerTypeICMPv4)
127                                                 if icmpLayer == nil {
128                                                         fmt.Println("Missing ICMPv4 layer.")
129                                                 }
130                                                 icmp, _ := icmpLayer.(*layers.ICMPv4)
131                                                 if icmp.TypeCode.Type() != layers.ICMPv4TypeEchoRequest {
132                                                         fmt.Println("Not ICMPv4 echo request.")
133                                                 }
134                                                 fmt.Println("Received an ICMPv4 echo request.")
135
136                                                 // Build packet layers.
137                                                 ethResp := layers.Ethernet{
138                                                         DstMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
139                                                         //DstMAC: net.HardwareAddr{0x02, 0xfe, 0xa8, 0x77, 0xaf, 0x20},
140                                                         SrcMAC: []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
141
142                                                         EthernetType: layers.EthernetTypeIPv4,
143                                                 }
144                                                 ipv4Resp := layers.IPv4{
145                                                         Version:    4,
146                                                         IHL:        5,
147                                                         TOS:        0,
148                                                         Id:         0,
149                                                         Flags:      0,
150                                                         FragOffset: 0,
151                                                         TTL:        255,
152                                                         Protocol:   layers.IPProtocolICMPv4,
153                                                         SrcIP:      []byte("\xc0\xa8\x01\x01"),
154                                                         DstIP:      []byte("\xc0\xa8\x01\x02"),
155                                                 }
156                                                 icmpResp := layers.ICMPv4{
157                                                         TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoReply, 0),
158                                                         Id:       icmp.Id,
159                                                         Seq:      icmp.Seq,
160                                                 }
161
162                                                 // Set up buffer and options for serialization.
163                                                 buf := gopacket.NewSerializeBuffer()
164                                                 opts := gopacket.SerializeOptions{
165                                                         FixLengths:       true,
166                                                         ComputeChecksums: true,
167                                                 }
168                                                 gopacket.SerializeLayers(buf, opts, &ethResp, &ipv4Resp, &icmpResp,
169                                                         gopacket.Payload(icmp.Payload))
170                                                 // write packet to shared memory
171                                                 txq0.WritePacket(buf.Bytes())
172                                         }
173                                 } else if err != nil {
174                                         errChan <- err
175                                         return
176                                 }
177                         }
178                 }
179         }(data.errChan, data.quitChan, &data.wg)
180
181         return nil
182 }
183
184 type interfaceData struct {
185         errChan  chan error
186         quitChan chan struct{}
187         wg       sync.WaitGroup
188 }
189
190 func interractiveHelp() {
191         fmt.Println("help - print this help")
192         fmt.Println("start - start connecting loop")
193         fmt.Println("show - print interface details")
194         fmt.Println("exit - exit the application")
195 }
196
197 func main() {
198         cpuprof := flag.String("cpuprof", "", "cpu profiling output file")
199         memprof := flag.String("memprof", "", "mem profiling output file")
200         role := flag.String("role", "slave", "interface role")
201         name := flag.String("name", "gomemif", "interface name")
202         socketName := flag.String("socket", "", "control socket filename")
203
204         flag.Parse()
205
206         if *cpuprof != "" {
207                 defer profile.Start(profile.CPUProfile, profile.ProfilePath(*cpuprof)).Stop()
208         }
209         if *memprof != "" {
210                 defer profile.Start(profile.MemProfile, profile.ProfilePath(*memprof)).Stop()
211         }
212
213         memifErrChan := make(chan error)
214         exitChan := make(chan struct{})
215
216         var isMaster bool
217         switch *role {
218         case "slave":
219                 isMaster = false
220         case "master":
221                 isMaster = true
222         default:
223                 fmt.Println("Invalid role")
224                 return
225         }
226
227         fmt.Println("GoMemif: Responder")
228         fmt.Println("-----------------------")
229
230         socket, err := memif.NewSocket("gomemif_example", *socketName)
231         if err != nil {
232                 fmt.Println("Failed to create socket: ", err)
233                 return
234         }
235
236         data := interfaceData{}
237         args := &memif.Arguments{
238                 IsMaster:         isMaster,
239                 ConnectedFunc:    Connected,
240                 DisconnectedFunc: Disconnected,
241                 PrivateData:      &data,
242                 Name:             *name,
243         }
244
245         i, err := socket.NewInterface(args)
246         if err != nil {
247                 fmt.Println("Failed to create interface on socket %s: %s", socket.GetFilename(), err)
248                 goto exit
249         }
250
251         // slave attempts to connect to control socket
252         // to handle control communication call socket.StartPolling()
253         if !i.IsMaster() {
254                 fmt.Println(args.Name, ": Connecting to control socket...")
255                 for !i.IsConnecting() {
256                         err = i.RequestConnection()
257                         if err != nil {
258                                 /* TODO: check for ECONNREFUSED errno
259                                  * if error is ECONNREFUSED it may simply mean that master
260                                  * interface is not up yet, use i.RequestConnection()
261                                  */
262                                 fmt.Println("Faild to connect: ", err)
263                                 goto exit
264                         }
265                 }
266         }
267
268         go func(exitChan chan<- struct{}) {
269                 reader := bufio.NewReader(os.Stdin)
270                 for {
271                         fmt.Print("gomemif# ")
272                         text, _ := reader.ReadString('\n')
273                         // convert CRLF to LF
274                         text = strings.Replace(text, "\n", "", -1)
275                         switch text {
276                         case "help":
277                                 interractiveHelp()
278                         case "start":
279                                 // start polling for events on this socket
280                                 socket.StartPolling(memifErrChan)
281                         case "show":
282                                 fmt.Println("remote: ", i.GetRemoteName())
283                                 fmt.Println("peer: ", i.GetPeerName())
284                         case "exit":
285                                 err = socket.StopPolling()
286                                 if err != nil {
287                                         fmt.Println("Failed to stop polling: ", err)
288                                 }
289                                 close(exitChan)
290                                 return
291                         default:
292                                 fmt.Println("Unknown input")
293                         }
294                 }
295         }(exitChan)
296
297         for {
298                 select {
299                 case <-exitChan:
300                         goto exit
301                 case err, ok := <-memifErrChan:
302                         if ok {
303                                 fmt.Println(err)
304                         }
305                 case err, ok := <-data.errChan:
306                         if ok {
307                                 fmt.Println(err)
308                         }
309                 default:
310                         continue
311                 }
312         }
313
314 exit:
315         socket.Delete()
316         close(memifErrChan)
317 }