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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
29 "github.com/pkg/profile"
33 func Disconnected(i *memif.Interface) error {
34 fmt.Println("Disconnected: ", i.GetName())
36 data, ok := i.GetPrivateData().(*interfaceData)
38 return fmt.Errorf("Invalid private data")
40 close(data.quitChan) // stop polling
42 data.wg.Wait() // wait until polling stops, then continue disconnect
47 func Connected(i *memif.Interface) error {
48 fmt.Println("Connected: ", i.GetName())
50 data, ok := i.GetPrivateData().(*interfaceData)
52 return fmt.Errorf("Invalid private data")
54 data.errChan = make(chan error, 1)
55 data.quitChan = make(chan struct{}, 1)
58 go func(errChan chan<- error, quitChan <-chan struct{}, wg *sync.WaitGroup) {
60 // allocate packet buffer
61 pkt := make([]byte, 2048)
63 rxq0, err := i.GetRxQueue(0)
69 // wait until both interfaces are connected
70 for !data.bri.IsConnected() {
71 time.Sleep(100 * time.Millisecond)
74 // get bridged interfaces tx queue
75 txq0, err := data.bri.GetTxQueue(0)
82 case <-quitChan: // channel closed
85 // read packet from shared memory
86 pktLen, err := rxq0.ReadPacket(pkt)
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 {
97 }(data.errChan, data.quitChan, &data.wg)
102 type interfaceData struct {
104 quitChan chan struct{}
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")
117 func newMemifInterface(socket *memif.Socket, id uint32, isMaster bool, name string) (*memif.Interface, *interfaceData, error) {
118 data := &interfaceData{}
119 args := &memif.Arguments{
122 ConnectedFunc: Connected,
123 DisconnectedFunc: Disconnected,
128 i, err := socket.NewInterface(args)
130 return nil, nil, fmt.Errorf("Failed to create interface on socket %s: %s", socket.GetFilename(), err)
133 // slave attempts to connect to control socket
134 // to handle control communication call socket.StartPolling()
136 fmt.Println(args.Name, ": Connecting to control socket...")
137 for !i.IsConnecting() {
138 err = i.RequestConnection()
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()
144 return nil, nil, fmt.Errorf("Faild to connect: ", err)
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())
160 fmt.Println("\tlink: ", link)
161 fmt.Println("\tremote: ", i.GetRemoteName())
162 fmt.Println("\tpeer: ", i.GetPeerName())
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)
172 memifErrChan := make(chan error)
173 exitChan := make(chan struct{})
174 var i0, i1 *memif.Interface
175 var d0, d1 *interfaceData
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")
187 defer profile.Start(profile.CPUProfile, profile.ProfilePath(*cpuprof)).Stop()
190 defer profile.Start(profile.MemProfile, profile.ProfilePath(*memprof)).Stop()
201 fmt.Println("Invalid role")
205 // create memif socket
206 socket, err := memif.NewSocket("gomemif_example", *socketName)
208 fmt.Println("Failed to create socket: ", err)
212 i0, d0, err = newMemifInterface(socket, 0, isMaster, *name)
219 i1, d1, err = newMemifInterface(socket, 1, isMaster, *name)
229 // user input goroutine
230 go func(exitChan chan<- struct{}) {
231 reader := bufio.NewReader(os.Stdin)
232 fmt.Println("GoMemif: Responder")
233 fmt.Println("-----------------------")
235 fmt.Print("gomemif# ")
236 text, _ := reader.ReadString('\n')
237 // convert CRLF to LF
238 text = strings.Replace(text, "\n", "", -1)
243 // start polling for events on this socket
244 socket.StartPolling(memifErrChan)
246 printMemifInterfaceDetails(i0)
247 printMemifInterfaceDetails(i1)
249 err = socket.StopPolling()
251 fmt.Println("Failed to stop polling: ", err)
256 fmt.Println("Unknown input")
266 case err, ok := <-memifErrChan:
270 case err, ok := <-d0.errChan:
274 case err, ok := <-d1.errChan: