ikev2: support responder hostname
[vpp.git] / extras / gomemif / examples / bridge.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         "os"
25         "strings"
26         "sync"
27         "time"
28
29         "github.com/pkg/profile"
30         "memif"
31 )
32
33 func Disconnected(i *memif.Interface) error {
34         fmt.Println("Disconnected: ", i.GetName())
35
36         data, ok := i.GetPrivateData().(*interfaceData)
37         if !ok {
38                 return fmt.Errorf("Invalid private data")
39         }
40         close(data.quitChan) // stop polling
41         close(data.errChan)
42         data.wg.Wait() // wait until polling stops, then continue disconnect
43
44         return nil
45 }
46
47 func Connected(i *memif.Interface) error {
48         fmt.Println("Connected: ", i.GetName())
49
50         data, ok := i.GetPrivateData().(*interfaceData)
51         if !ok {
52                 return fmt.Errorf("Invalid private data")
53         }
54         data.errChan = make(chan error, 1)
55         data.quitChan = make(chan struct{}, 1)
56         data.wg.Add(1)
57
58         go func(errChan chan<- error, quitChan <-chan struct{}, wg *sync.WaitGroup) {
59                 defer wg.Done()
60                 // allocate packet buffer
61                 pkt := make([]byte, 2048)
62                 // get rx queue
63                 rxq0, err := i.GetRxQueue(0)
64                 if err != nil {
65                         errChan <- err
66                         return
67                 }
68
69                 // wait until both interfaces are connected
70                 for !data.bri.IsConnected() {
71                         time.Sleep(100 * time.Millisecond)
72                 }
73
74                 // get bridged interfaces tx queue
75                 txq0, err := data.bri.GetTxQueue(0)
76                 if err != nil {
77                         errChan <- err
78                         return
79                 }
80                 for {
81                         select {
82                         case <-quitChan: // channel closed
83                                 return
84                         default:
85                                 // read packet from shared memory
86                                 pktLen, err := rxq0.ReadPacket(pkt)
87                                 if pktLen > 0 {
88                                         // FIXME: prevent packet write if interface is disconencted
89                                         // write packet to shared memory
90                                         txq0.WritePacket(pkt[:pktLen])
91                                 } else if err != nil {
92                                         errChan <- err
93                                         return
94                                 }
95                         }
96                 }
97         }(data.errChan, data.quitChan, &data.wg)
98
99         return nil
100 }
101
102 type interfaceData struct {
103         errChan  chan error
104         quitChan chan struct{}
105         wg       sync.WaitGroup
106         // bridged interface
107         bri *memif.Interface
108 }
109
110 func interractiveHelp() {
111         fmt.Println("help - print this help")
112         fmt.Println("start - start connecting loop")
113         fmt.Println("show - print interface details")
114         fmt.Println("exit - exit the application")
115 }
116
117 func newMemifInterface(socket *memif.Socket, id uint32, isMaster bool, name string) (*memif.Interface, *interfaceData, error) {
118         data := &interfaceData{}
119         args := &memif.Arguments{
120                 Id:               id,
121                 IsMaster:         isMaster,
122                 ConnectedFunc:    Connected,
123                 DisconnectedFunc: Disconnected,
124                 PrivateData:      data,
125                 Name:             name,
126         }
127
128         i, err := socket.NewInterface(args)
129         if err != nil {
130                 return nil, nil, fmt.Errorf("Failed to create interface on socket %s: %s", socket.GetFilename(), err)
131         }
132
133         // slave attempts to connect to control socket
134         // to handle control communication call socket.StartPolling()
135         if !i.IsMaster() {
136                 fmt.Println(args.Name, ": Connecting to control socket...")
137                 for !i.IsConnecting() {
138                         err = i.RequestConnection()
139                         if err != nil {
140                                 /* TODO: check for ECONNREFUSED errno
141                                  * if error is ECONNREFUSED it may simply mean that master
142                                  * interface is not up yet, use i.RequestConnection()
143                                  */
144                                 return nil, nil, fmt.Errorf("Faild to connect: ", err)
145                         }
146                 }
147         }
148
149         return i, data, nil
150 }
151
152 func printMemifInterfaceDetails(i *memif.Interface) {
153         fmt.Println(i.GetName(), ":")
154         fmt.Println("\trole: ", memif.RoleToString(i.IsMaster()))
155         fmt.Println("\tid: ", i.GetId())
156         link := "down"
157         if i.IsConnected() {
158                 link = "up"
159         }
160         fmt.Println("\tlink: ", link)
161         fmt.Println("\tremote: ", i.GetRemoteName())
162         fmt.Println("\tpeer: ", i.GetPeerName())
163         if i.IsConnected() {
164                 mc := i.GetMemoryConfig()
165                 fmt.Println("queue pairs: ", mc.NumQueuePairs)
166                 fmt.Println("ring size: ", (1 << mc.Log2RingSize))
167                 fmt.Println("buffer size: ", mc.PacketBufferSize)
168         }
169 }
170
171 func main() {
172         memifErrChan := make(chan error)
173         exitChan := make(chan struct{})
174         var i0, i1 *memif.Interface
175         var d0, d1 *interfaceData
176
177         cpuprof := flag.String("cpuprof", "", "cpu profiling output file")
178         memprof := flag.String("memprof", "", "mem profiling output file")
179         role := flag.String("role", "slave", "interface role")
180         name := flag.String("name", "gomemif", "interface name")
181         socketName := flag.String("socket", "", "control socket filename")
182
183         flag.Parse()
184
185         // profiling options
186         if *cpuprof != "" {
187                 defer profile.Start(profile.CPUProfile, profile.ProfilePath(*cpuprof)).Stop()
188         }
189         if *memprof != "" {
190                 defer profile.Start(profile.MemProfile, profile.ProfilePath(*memprof)).Stop()
191         }
192
193         // memif options
194         var isMaster bool
195         switch *role {
196         case "slave":
197                 isMaster = false
198         case "master":
199                 isMaster = true
200         default:
201                 fmt.Println("Invalid role")
202                 return
203         }
204
205         // create memif socket
206         socket, err := memif.NewSocket("gomemif_example", *socketName)
207         if err != nil {
208                 fmt.Println("Failed to create socket: ", err)
209                 return
210         }
211
212         i0, d0, err = newMemifInterface(socket, 0, isMaster, *name)
213         if err != nil {
214                 fmt.Println(err)
215                 goto exit
216         }
217
218         // TODO: update name
219         i1, d1, err = newMemifInterface(socket, 1, isMaster, *name)
220         if err != nil {
221                 fmt.Println(err)
222                 goto exit
223         }
224
225         // set up bridge
226         d0.bri = i1
227         d1.bri = i0
228
229         // user input goroutine
230         go func(exitChan chan<- struct{}) {
231                 reader := bufio.NewReader(os.Stdin)
232                 fmt.Println("GoMemif: Responder")
233                 fmt.Println("-----------------------")
234                 for {
235                         fmt.Print("gomemif# ")
236                         text, _ := reader.ReadString('\n')
237                         // convert CRLF to LF
238                         text = strings.Replace(text, "\n", "", -1)
239                         switch text {
240                         case "help":
241                                 interractiveHelp()
242                         case "start":
243                                 // start polling for events on this socket
244                                 socket.StartPolling(memifErrChan)
245                         case "show":
246                                 printMemifInterfaceDetails(i0)
247                                 printMemifInterfaceDetails(i1)
248                         case "exit":
249                                 err = socket.StopPolling()
250                                 if err != nil {
251                                         fmt.Println("Failed to stop polling: ", err)
252                                 }
253                                 close(exitChan)
254                                 return
255                         default:
256                                 fmt.Println("Unknown input")
257                         }
258                 }
259         }(exitChan)
260
261         // main loop
262         for {
263                 select {
264                 case <-exitChan:
265                         goto exit
266                 case err, ok := <-memifErrChan:
267                         if ok {
268                                 fmt.Println(err)
269                         }
270                 case err, ok := <-d0.errChan:
271                         if ok {
272                                 fmt.Println(err)
273                         }
274                 case err, ok := <-d1.errChan:
275                         if ok {
276                                 fmt.Println(err)
277                         }
278                 default:
279                         continue
280                 }
281         }
282
283 exit:
284         socket.Delete()
285         close(memifErrChan)
286 }