summaryrefslogtreecommitdiffstats
path: root/extras/gomemif/examples/icmp_responder_cb.go
diff options
context:
space:
mode:
Diffstat (limited to 'extras/gomemif/examples/icmp_responder_cb.go')
-rw-r--r--extras/gomemif/examples/icmp_responder_cb.go326
1 files changed, 326 insertions, 0 deletions
diff --git a/extras/gomemif/examples/icmp_responder_cb.go b/extras/gomemif/examples/icmp_responder_cb.go
new file mode 100644
index 00000000000..8d8adcfc892
--- /dev/null
+++ b/extras/gomemif/examples/icmp_responder_cb.go
@@ -0,0 +1,326 @@
+/*
+ *------------------------------------------------------------------
+ * 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"
+ "net"
+ "os"
+ "strings"
+ "sync"
+
+ "memif"
+
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/pkg/profile"
+)
+
+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 Responder(i *memif.Interface) error {
+ 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)
+
+ // allocate packet buffer
+ pkt := make([]byte, 2048)
+ // get rx queue
+ rxq0, err := i.GetRxQueue(0)
+ if err != nil {
+ return err
+ }
+ // get tx queue
+ txq0, err := i.GetTxQueue(0)
+ if err != nil {
+ return err
+ }
+ for {
+
+ // read packet from shared memory
+ pktLen, err := rxq0.ReadPacket(pkt)
+ _ = err
+ if pktLen > 0 {
+ fmt.Printf("pktLen: %d\n", pktLen)
+ gopkt := gopacket.NewPacket(pkt[:pktLen], layers.LayerTypeEthernet, gopacket.NoCopy)
+ etherLayer := gopkt.Layer(layers.LayerTypeEthernet)
+ if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeARP {
+ rEth := layers.Ethernet{
+ SrcMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
+ DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+
+ EthernetType: layers.EthernetTypeARP,
+ }
+ rArp := layers.ARP{
+ AddrType: layers.LinkTypeEthernet,
+ Protocol: layers.EthernetTypeIPv4,
+ HwAddressSize: 6,
+ ProtAddressSize: 4,
+ Operation: layers.ARPReply,
+ SourceHwAddress: []byte(net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}),
+ SourceProtAddress: []byte("\xc0\xa8\x01\x01"),
+ DstHwAddress: []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
+ DstProtAddress: []byte("\xc0\xa8\x01\x02"),
+ }
+ buf := gopacket.NewSerializeBuffer()
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ gopacket.SerializeLayers(buf, opts, &rEth, &rArp)
+ // write packet to shared memory
+ txq0.WritePacket(buf.Bytes())
+ }
+
+ if etherLayer.(*layers.Ethernet).EthernetType == layers.EthernetTypeIPv4 {
+ ipLayer := gopkt.Layer(layers.LayerTypeIPv4)
+ if ipLayer == nil {
+ fmt.Println("Missing IPv4 layer.")
+
+ }
+ ipv4, _ := ipLayer.(*layers.IPv4)
+ if ipv4.Protocol != layers.IPProtocolICMPv4 {
+ fmt.Println("Not ICMPv4 protocol.")
+ }
+ icmpLayer := gopkt.Layer(layers.LayerTypeICMPv4)
+ if icmpLayer == nil {
+ fmt.Println("Missing ICMPv4 layer.")
+ }
+ icmp, _ := icmpLayer.(*layers.ICMPv4)
+ if icmp.TypeCode.Type() != layers.ICMPv4TypeEchoRequest {
+ fmt.Println("Not ICMPv4 echo request.")
+ }
+ fmt.Println("Received an ICMPv4 echo request.")
+
+ // Build packet layers.
+ ethResp := layers.Ethernet{
+ DstMAC: net.HardwareAddr{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa},
+ //DstMAC: net.HardwareAddr{0x02, 0xfe, 0xa8, 0x77, 0xaf, 0x20},
+ SrcMAC: []byte(net.HardwareAddr{0x02, 0xfe, 0x08, 0x88, 0x45, 0x7f}),
+
+ EthernetType: layers.EthernetTypeIPv4,
+ }
+ ipv4Resp := layers.IPv4{
+ Version: 4,
+ IHL: 5,
+ TOS: 0,
+ Id: 0,
+ Flags: 0,
+ FragOffset: 0,
+ TTL: 255,
+ Protocol: layers.IPProtocolICMPv4,
+ SrcIP: []byte("\xc0\xa8\x01\x01"),
+ DstIP: []byte("\xc0\xa8\x01\x02"),
+ }
+ icmpResp := layers.ICMPv4{
+ TypeCode: layers.CreateICMPv4TypeCode(layers.ICMPv4TypeEchoReply, 0),
+ Id: icmp.Id,
+ Seq: icmp.Seq,
+ }
+
+ // Set up buffer and options for serialization.
+ buf := gopacket.NewSerializeBuffer()
+ opts := gopacket.SerializeOptions{
+ FixLengths: true,
+ ComputeChecksums: true,
+ }
+ gopacket.SerializeLayers(buf, opts, &ethResp, &ipv4Resp, &icmpResp,
+ gopacket.Payload(icmp.Payload))
+ // write packet to shared memory
+ txq0.WritePacket(buf.Bytes())
+ }
+
+ }
+ return nil
+
+ }
+
+}
+func Connected(i *memif.Interface) error {
+ data, ok := i.GetPrivateData().(*interfaceData)
+ if !ok {
+ return fmt.Errorf("Invalid private data")
+ }
+ _ = data
+
+ // allocate packet buffer
+ pkt := make([]byte, 2048)
+ // get rx queue
+ rxq0, err := i.GetRxQueue(0)
+ _ = err
+
+ // read packet from shared memory
+ pktLen, err := rxq0.ReadPacket(pkt)
+ _, _ = err, pktLen
+
+ 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", "/run/vpp/memif.sock", "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,
+ InterruptFunc: Responder,
+ }
+
+ 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("Failed 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)
+}