blob: a192034e3be48d19142ce990f33c8b8f6523afc1 [file] [log] [blame]
Jakub Grajciar07363a42020-04-02 10:02:17 +02001/*
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
18package main
19
20import (
21 "bufio"
22 "flag"
23 "fmt"
24 "os"
25 "strings"
26 "sync"
27 "time"
28
29 "github.com/pkg/profile"
30 "memif"
31)
32
33func 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
47func 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
102type interfaceData struct {
103 errChan chan error
104 quitChan chan struct{}
105 wg sync.WaitGroup
106 // bridged interface
107 bri *memif.Interface
108}
109
110func 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
117func 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
152func 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
171func 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
283exit:
284 socket.Delete()
285 close(memifErrChan)
286}