summaryrefslogtreecommitdiffstats
path: root/extras/gomemif/examples/responder.go
diff options
context:
space:
mode:
Diffstat (limited to 'extras/gomemif/examples/responder.go')
-rw-r--r--extras/gomemif/examples/responder.go227
1 files changed, 227 insertions, 0 deletions
diff --git a/extras/gomemif/examples/responder.go b/extras/gomemif/examples/responder.go
new file mode 100644
index 00000000000..8fda6435bc5
--- /dev/null
+++ b/extras/gomemif/examples/responder.go
@@ -0,0 +1,227 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2020 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+ "sync"
+
+ "github.com/pkg/profile"
+ "memif"
+)
+
+func Disconnected(i *memif.Interface) error {
+ fmt.Println("Disconnected: ", i.GetName())
+
+ data, ok := i.GetPrivateData().(*interfaceData)
+ if !ok {
+ return fmt.Errorf("Invalid private data")
+ }
+ close(data.quitChan) // stop polling
+ close(data.errChan)
+ data.wg.Wait() // wait until polling stops, then continue disconnect
+
+ return nil
+}
+
+func Connected(i *memif.Interface) error {
+ fmt.Println("Connected: ", i.GetName())
+
+ data, ok := i.GetPrivateData().(*interfaceData)
+ if !ok {
+ return fmt.Errorf("Invalid private data")
+ }
+ data.errChan = make(chan error, 1)
+ data.quitChan = make(chan struct{}, 1)
+ data.wg.Add(1)
+
+ go func(errChan chan<- error, quitChan <-chan struct{}, wg *sync.WaitGroup) {
+ defer wg.Done()
+ // allocate packet buffer
+ pkt := make([]byte, 2048)
+ // get rx queue
+ rxq0, err := i.GetRxQueue(0)
+ if err != nil {
+ errChan <- err
+ return
+ }
+ // get tx queue
+ txq0, err := i.GetTxQueue(0)
+ if err != nil {
+ errChan <- err
+ return
+ }
+ for {
+ select {
+ case <-quitChan: // channel closed
+ return
+ default:
+ // read packet from shared memory
+ pktLen, err := rxq0.ReadPacket(pkt)
+ if pktLen > 0 {
+ // write packet to shared memory
+ txq0.WritePacket(pkt[:pktLen])
+ } else if err != nil {
+ errChan <- err
+ return
+ }
+ }
+ }
+ }(data.errChan, data.quitChan, &data.wg)
+
+ return nil
+}
+
+type interfaceData struct {
+ errChan chan error
+ quitChan chan struct{}
+ wg sync.WaitGroup
+}
+
+func interractiveHelp() {
+ fmt.Println("help - print this help")
+ fmt.Println("start - start connecting loop")
+ fmt.Println("show - print interface details")
+ fmt.Println("exit - exit the application")
+}
+
+func main() {
+ cpuprof := flag.String("cpuprof", "", "cpu profiling output file")
+ memprof := flag.String("memprof", "", "mem profiling output file")
+ role := flag.String("role", "slave", "interface role")
+ name := flag.String("name", "gomemif", "interface name")
+ socketName := flag.String("socket", "", "control socket filename")
+
+ flag.Parse()
+
+ if *cpuprof != "" {
+ defer profile.Start(profile.CPUProfile, profile.ProfilePath(*cpuprof)).Stop()
+ }
+ if *memprof != "" {
+ defer profile.Start(profile.MemProfile, profile.ProfilePath(*memprof)).Stop()
+ }
+
+ memifErrChan := make(chan error)
+ exitChan := make(chan struct{})
+
+ var isMaster bool
+ switch *role {
+ case "slave":
+ isMaster = false
+ case "master":
+ isMaster = true
+ default:
+ fmt.Println("Invalid role")
+ return
+ }
+
+ fmt.Println("GoMemif: Responder")
+ fmt.Println("-----------------------")
+
+ socket, err := memif.NewSocket("gomemif_example", *socketName)
+ if err != nil {
+ fmt.Println("Failed to create socket: ", err)
+ return
+ }
+
+ data := interfaceData{}
+ args := &memif.Arguments{
+ IsMaster: isMaster,
+ ConnectedFunc: Connected,
+ DisconnectedFunc: Disconnected,
+ PrivateData: &data,
+ Name: *name,
+ }
+
+ i, err := socket.NewInterface(args)
+ if err != nil {
+ fmt.Println("Failed to create interface on socket %s: %s", socket.GetFilename(), err)
+ goto exit
+ }
+
+ // slave attempts to connect to control socket
+ // to handle control communication call socket.StartPolling()
+ if !i.IsMaster() {
+ fmt.Println(args.Name, ": Connecting to control socket...")
+ for !i.IsConnecting() {
+ err = i.RequestConnection()
+ if err != nil {
+ /* TODO: check for ECONNREFUSED errno
+ * if error is ECONNREFUSED it may simply mean that master
+ * interface is not up yet, use i.RequestConnection()
+ */
+ fmt.Println("Faild to connect: ", err)
+ goto exit
+ }
+ }
+ }
+
+ go func(exitChan chan<- struct{}) {
+ reader := bufio.NewReader(os.Stdin)
+ for {
+ fmt.Print("gomemif# ")
+ text, _ := reader.ReadString('\n')
+ // convert CRLF to LF
+ text = strings.Replace(text, "\n", "", -1)
+ switch text {
+ case "help":
+ interractiveHelp()
+ case "start":
+ // start polling for events on this socket
+ socket.StartPolling(memifErrChan)
+ case "show":
+ fmt.Println("remote: ", i.GetRemoteName())
+ fmt.Println("peer: ", i.GetPeerName())
+ case "exit":
+ err = socket.StopPolling()
+ if err != nil {
+ fmt.Println("Failed to stop polling: ", err)
+ }
+ close(exitChan)
+ return
+ default:
+ fmt.Println("Unknown input")
+ }
+ }
+ }(exitChan)
+
+ for {
+ select {
+ case <-exitChan:
+ goto exit
+ case err, ok := <-memifErrChan:
+ if ok {
+ fmt.Println(err)
+ }
+ case err, ok := <-data.errChan:
+ if ok {
+ fmt.Println(err)
+ }
+ default:
+ continue
+ }
+ }
+
+exit:
+ socket.Delete()
+ close(memifErrChan)
+}