gomemif: migrate to govpp repository
Type: make
Signed-off-by: Matus Halaj <mhalaj@cisco.com>
Change-Id: I1d48c7e44fdf23438132996fd3288b29da1fe36e
diff --git a/extras/gomemif/BUILD.bazel b/extras/gomemif/BUILD.bazel
deleted file mode 100644
index e69de29..0000000
--- a/extras/gomemif/BUILD.bazel
+++ /dev/null
diff --git a/extras/gomemif/README.rst b/extras/gomemif/README.rst
deleted file mode 100644
index 18f3828..0000000
--- a/extras/gomemif/README.rst
+++ /dev/null
@@ -1,50 +0,0 @@
-.. _gomemif_doc:
-
-Gomemif library
-=======================
-
-Memif library implemented in Go. The package contains 3 examples: Bridge and ICMP responder in interrupt and polling mode.
-
-setup and run
--------------
-To Build all examples
-
-::
-
- bazel build //...
-
-To Run ICMP responder in interrupt mode:
-
-::
-
- DBGvpp# create interface memif id 0 master no-zero-copy
- DBGvpp# set int ip addr memif0/0 192.168.1.2/24
- DBGvpp# set int state memif0/0 up
-
- bazel-bin/examples/linux_amd64_stripped/icmp_responder_cb
- gomemif# start
-
- DBGvpp# ping 192.168.1.1
-
-To Run ICMP responder in polling mode:
-
-::
-
- DBGvpp# create interface memif id 0 master no-zero-copy
- DBGvpp# set int ip addr memif0/0 192.168.1.2/24
- DBGvpp# set int state memif0/0 up
-
- bazel-bin/examples/linux_amd64_stripped/icmp_responder_poll
- gomemif# start
-
- DBGvpp# ping 192.168.1.1
-
-To Run Bridge:
-
-::
-
- bazel-bin/examples/linux_amd64_stripped/bridge
- gomemif# start
-
-
-
diff --git a/extras/gomemif/WORKSPACE b/extras/gomemif/WORKSPACE
deleted file mode 100644
index d75bfa5..0000000
--- a/extras/gomemif/WORKSPACE
+++ /dev/null
@@ -1,40 +0,0 @@
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-http_archive(
- name = "io_bazel_rules_go",
- urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.21.2/rules_go-v0.21.2.tar.gz",
- "https://github.com/bazelbuild/rules_go/releases/download/v0.21.2/rules_go-v0.21.2.tar.gz",
- ],
- sha256 = "f99a9d76e972e0c8f935b2fe6d0d9d778f67c760c6d2400e23fc2e469016e2bd",
-)
-
-load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")
-
-http_archive(
- name = "bazel_gazelle",
- sha256 = "86c6d481b3f7aedc1d60c1c211c6f76da282ae197c3b3160f54bd3a8f847896f",
- urls = [
- "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/bazel-gazelle/releases/download/v0.19.1/bazel-gazelle-v0.19.1.tar.gz",
- "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.19.1/bazel-gazelle-v0.19.1.tar.gz",
- ],
-)
-
-go_rules_dependencies()
-
-go_register_toolchains()
-
-load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
-
-gazelle_dependencies()
-
-go_repository(
- name = "com_github_profile",
- importpath = "github.com/pkg/profile",
- commit = "acd64d450fd45fb2afa41f833f3788c8a7797219"
-)
-go_repository(
- name = "com_github_gopacket",
- importpath = "github.com/google/gopacket",
- commit = "3eaba08943250fd212520e5cff00ed808b8fc60a"
-)
diff --git a/extras/gomemif/examples/BUILD.bazel b/extras/gomemif/examples/BUILD.bazel
deleted file mode 100644
index eb10422..0000000
--- a/extras/gomemif/examples/BUILD.bazel
+++ /dev/null
@@ -1,36 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_binary")
-
-go_binary(
- name = "icmp_responder_poll",
- srcs = ["icmp_responder_poll.go"],
- visibility = ["//visibility:public",],
- deps = [
- "//memif:memif",
- "@com_github_profile//:go_default_library",
- "@com_github_gopacket//layers:go_default_library",
- "@com_github_gopacket//:go_default_library"
- ],
-)
-
-go_binary(
- name = "bridge",
- srcs = ["bridge.go"],
- visibility = ["//visibility:public",],
- deps = [
- "//memif:memif",
- "@com_github_profile//:go_default_library",
- ],
-)
-
-go_binary(
- name = "icmp_responder_cb",
- srcs = ["icmp_responder_cb.go"],
- visibility = ["//visibility:public",],
- deps = [
- "//memif:memif",
- "@com_github_profile//:go_default_library",
- "@com_github_gopacket//layers:go_default_library",
- "@com_github_gopacket//:go_default_library"
- ],
-)
-
diff --git a/extras/gomemif/examples/bridge.go b/extras/gomemif/examples/bridge.go
deleted file mode 100644
index a192034..0000000
--- a/extras/gomemif/examples/bridge.go
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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"
- "time"
-
- "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
- }
-
- // wait until both interfaces are connected
- for !data.bri.IsConnected() {
- time.Sleep(100 * time.Millisecond)
- }
-
- // get bridged interfaces tx queue
- txq0, err := data.bri.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 {
- // FIXME: prevent packet write if interface is disconencted
- // 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
- // bridged interface
- bri *memif.Interface
-}
-
-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 newMemifInterface(socket *memif.Socket, id uint32, isMaster bool, name string) (*memif.Interface, *interfaceData, error) {
- data := &interfaceData{}
- args := &memif.Arguments{
- Id: id,
- IsMaster: isMaster,
- ConnectedFunc: Connected,
- DisconnectedFunc: Disconnected,
- PrivateData: data,
- Name: name,
- }
-
- i, err := socket.NewInterface(args)
- if err != nil {
- return nil, nil, fmt.Errorf("Failed to create interface on socket %s: %s", socket.GetFilename(), err)
- }
-
- // 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()
- */
- return nil, nil, fmt.Errorf("Faild to connect: ", err)
- }
- }
- }
-
- return i, data, nil
-}
-
-func printMemifInterfaceDetails(i *memif.Interface) {
- fmt.Println(i.GetName(), ":")
- fmt.Println("\trole: ", memif.RoleToString(i.IsMaster()))
- fmt.Println("\tid: ", i.GetId())
- link := "down"
- if i.IsConnected() {
- link = "up"
- }
- fmt.Println("\tlink: ", link)
- fmt.Println("\tremote: ", i.GetRemoteName())
- fmt.Println("\tpeer: ", i.GetPeerName())
- if i.IsConnected() {
- mc := i.GetMemoryConfig()
- fmt.Println("queue pairs: ", mc.NumQueuePairs)
- fmt.Println("ring size: ", (1 << mc.Log2RingSize))
- fmt.Println("buffer size: ", mc.PacketBufferSize)
- }
-}
-
-func main() {
- memifErrChan := make(chan error)
- exitChan := make(chan struct{})
- var i0, i1 *memif.Interface
- var d0, d1 *interfaceData
-
- 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()
-
- // profiling options
- if *cpuprof != "" {
- defer profile.Start(profile.CPUProfile, profile.ProfilePath(*cpuprof)).Stop()
- }
- if *memprof != "" {
- defer profile.Start(profile.MemProfile, profile.ProfilePath(*memprof)).Stop()
- }
-
- // memif options
- var isMaster bool
- switch *role {
- case "slave":
- isMaster = false
- case "master":
- isMaster = true
- default:
- fmt.Println("Invalid role")
- return
- }
-
- // create memif socket
- socket, err := memif.NewSocket("gomemif_example", *socketName)
- if err != nil {
- fmt.Println("Failed to create socket: ", err)
- return
- }
-
- i0, d0, err = newMemifInterface(socket, 0, isMaster, *name)
- if err != nil {
- fmt.Println(err)
- goto exit
- }
-
- // TODO: update name
- i1, d1, err = newMemifInterface(socket, 1, isMaster, *name)
- if err != nil {
- fmt.Println(err)
- goto exit
- }
-
- // set up bridge
- d0.bri = i1
- d1.bri = i0
-
- // user input goroutine
- go func(exitChan chan<- struct{}) {
- reader := bufio.NewReader(os.Stdin)
- fmt.Println("GoMemif: Responder")
- fmt.Println("-----------------------")
- 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":
- printMemifInterfaceDetails(i0)
- printMemifInterfaceDetails(i1)
- case "exit":
- err = socket.StopPolling()
- if err != nil {
- fmt.Println("Failed to stop polling: ", err)
- }
- close(exitChan)
- return
- default:
- fmt.Println("Unknown input")
- }
- }
- }(exitChan)
-
- // main loop
- for {
- select {
- case <-exitChan:
- goto exit
- case err, ok := <-memifErrChan:
- if ok {
- fmt.Println(err)
- }
- case err, ok := <-d0.errChan:
- if ok {
- fmt.Println(err)
- }
- case err, ok := <-d1.errChan:
- if ok {
- fmt.Println(err)
- }
- default:
- continue
- }
- }
-
-exit:
- socket.Delete()
- close(memifErrChan)
-}
diff --git a/extras/gomemif/examples/icmp_responder_cb.go b/extras/gomemif/examples/icmp_responder_cb.go
deleted file mode 100644
index 8d8adcf..0000000
--- a/extras/gomemif/examples/icmp_responder_cb.go
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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, ðResp, &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)
-}
diff --git a/extras/gomemif/examples/icmp_responder_poll.go b/extras/gomemif/examples/icmp_responder_poll.go
deleted file mode 100644
index f9f1c3e..0000000
--- a/extras/gomemif/examples/icmp_responder_poll.go
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 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 {
- 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, ðResp, &ipv4Resp, &icmpResp,
- gopacket.Payload(icmp.Payload))
- // write packet to shared memory
- txq0.WritePacket(buf.Bytes())
- }
- } 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)
-}
diff --git a/extras/gomemif/memif/BUILD.bazel b/extras/gomemif/memif/BUILD.bazel
deleted file mode 100644
index e6539ff..0000000
--- a/extras/gomemif/memif/BUILD.bazel
+++ /dev/null
@@ -1,17 +0,0 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
-
-go_library(
- name = "memif",
- srcs = [
- "interface.go",
- "interface_unsafe.go",
- "control_channel.go",
- "control_channel_unsafe.go",
- "memif.go",
- "memif_unsafe.go",
- "packet_writer.go",
- "packet_reader.go",
- ],
- importpath = "memif",
- visibility = ["//visibility:public",],
-)
diff --git a/extras/gomemif/memif/control_channel.go b/extras/gomemif/memif/control_channel.go
deleted file mode 100644
index 4788fcb..0000000
--- a/extras/gomemif/memif/control_channel.go
+++ /dev/null
@@ -1,1001 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 memif
-
-import (
- "bytes"
- "container/list"
- "encoding/binary"
- "fmt"
- "os"
- "sync"
- "syscall"
-)
-
-const maxEpollEvents = 1
-const maxControlLen = 256
-
-const errorFdNotFound = "fd not found"
-
-// controlMsg represents a message used in communication between memif peers
-type controlMsg struct {
- Buffer *bytes.Buffer
- Fd int
-}
-
-// listener represents a listener functionality of UNIX domain socket
-type listener struct {
- socket *Socket
- event syscall.EpollEvent
-}
-
-// controlChannel represents a communication channel between memif peers
-// backed by UNIX domain socket
-type controlChannel struct {
- listRef *list.Element
- socket *Socket
- i *Interface
- event syscall.EpollEvent
- data [msgSize]byte
- control [maxControlLen]byte
- controlLen int
- msgQueue []controlMsg
- isConnected bool
-}
-
-// Socket represents a UNIX domain socket used for communication
-// between memif peers
-type Socket struct {
- appName string
- filename string
- listener *listener
- interfaceList *list.List
- ccList *list.List
- epfd int
- interruptfd int
- wakeEvent syscall.EpollEvent
- stopPollChan chan struct{}
- wg sync.WaitGroup
-}
-
-type interrupt struct {
- socket *Socket
- event syscall.EpollEvent
-}
-
-type memifInterrupt struct {
- connection *Socket
- qid uint16
-}
-
-// StopPolling stops polling events on the socket
-func (socket *Socket) StopPolling() error {
- if socket.stopPollChan != nil {
- // stop polling msg
- close(socket.stopPollChan)
- // wake epoll
- buf := make([]byte, 8)
- binary.PutUvarint(buf, 1)
- n, err := syscall.Write(int(socket.wakeEvent.Fd), buf[:])
- if err != nil {
- return err
- }
- if n != 8 {
- return fmt.Errorf("Faild to write to eventfd")
- }
- // wait until polling is stopped
- socket.wg.Wait()
- }
-
- return nil
-}
-
-// StartPolling starts polling and handling events on the socket,
-// enabling communication between memif peers
-func (socket *Socket) StartPolling(errChan chan<- error) {
- socket.stopPollChan = make(chan struct{})
- socket.wg.Add(1)
- go func() {
- var events [maxEpollEvents]syscall.EpollEvent
- defer socket.wg.Done()
-
- for {
- select {
- case <-socket.stopPollChan:
- return
- default:
- num, err := syscall.EpollWait(socket.epfd, events[:], -1)
- if err != nil {
- errChan <- fmt.Errorf("EpollWait: ", err)
- return
- }
-
- for ev := 0; ev < num; ev++ {
- if events[0].Fd == socket.wakeEvent.Fd {
- continue
- }
- err = socket.handleEvent(&events[0])
- if err != nil {
- errChan <- fmt.Errorf("handleEvent: ", err)
- }
- }
- }
- }
- }()
-}
-
-// addEvent adds event to epoll instance associated with the socket
-func (socket *Socket) addEvent(event *syscall.EpollEvent) error {
- err := syscall.EpollCtl(socket.epfd, syscall.EPOLL_CTL_ADD, int(event.Fd), event)
- if err != nil {
- return fmt.Errorf("EpollCtl: %s", err)
- }
- return nil
-}
-
-// addEvent deletes event to epoll instance associated with the socket
-func (socket *Socket) delEvent(event *syscall.EpollEvent) error {
- err := syscall.EpollCtl(socket.epfd, syscall.EPOLL_CTL_DEL, int(event.Fd), event)
- if err != nil {
- return fmt.Errorf("EpollCtl: %s", err)
- }
- return nil
-}
-
-// Delete deletes the socket
-func (socket *Socket) Delete() (err error) {
- for elt := socket.ccList.Front(); elt != nil; elt = elt.Next() {
- cc, ok := elt.Value.(*controlChannel)
- if ok {
- err = cc.close(true, "Socket deleted")
- if err != nil {
- return nil
- }
- }
- }
- for elt := socket.interfaceList.Front(); elt != nil; elt = elt.Next() {
- i, ok := elt.Value.(*Interface)
- if ok {
- err = i.Delete()
- if err != nil {
- return err
- }
- }
- }
-
- if socket.listener != nil {
- err = socket.listener.close()
- if err != nil {
- return err
- }
- err = os.Remove(socket.filename)
- if err != nil {
- return nil
- }
- }
-
- err = socket.delEvent(&socket.wakeEvent)
- if err != nil {
- return fmt.Errorf("Failed to delete event: ", err)
- }
-
- syscall.Close(socket.epfd)
-
- return nil
-}
-
-// NewSocket returns a new Socket
-func NewSocket(appName string, filename string) (socket *Socket, err error) {
- socket = &Socket{
- appName: appName,
- filename: filename,
- interfaceList: list.New(),
- ccList: list.New(),
- }
- if socket.filename == "" {
- socket.filename = DefaultSocketFilename
- }
-
- socket.epfd, _ = syscall.EpollCreate1(0)
-
- efd, err := eventFd()
- socket.wakeEvent = syscall.EpollEvent{
- Events: syscall.EPOLLIN | syscall.EPOLLERR | syscall.EPOLLHUP,
- Fd: int32(efd),
- }
- err = socket.addEvent(&socket.wakeEvent)
- if err != nil {
- return nil, fmt.Errorf("Failed to add event: ", err)
- }
-
- return socket, nil
-}
-
-// handleEvent handles epoll event
-func (socket *Socket) handleEvent(event *syscall.EpollEvent) error {
- if socket.listener != nil && socket.listener.event.Fd == event.Fd {
- return socket.listener.handleEvent(event)
- }
- intf := socket.interfaceList.Back().Value.(*Interface)
- if intf.args.InterruptFunc != nil {
- if int(event.Fd) == int(intf.args.InterruptFd) {
- b := make([]byte, 8)
- syscall.Read(int(event.Fd), b)
- intf.onInterrupt(intf)
- return nil
- }
- }
-
- for elt := socket.ccList.Front(); elt != nil; elt = elt.Next() {
- cc, ok := elt.Value.(*controlChannel)
- if ok {
- if cc.event.Fd == event.Fd {
- return cc.handleEvent(event)
- }
- }
- }
-
- return fmt.Errorf(errorFdNotFound)
-}
-
-func (socket *Socket) addInterrupt(fd int) (err error) {
- l := &interrupt{
- // we will need this to look up master interface by id
- socket: socket,
- }
-
- l.event = syscall.EpollEvent{
- Events: syscall.EPOLLIN,
- Fd: int32(fd),
- }
- err = socket.addEvent(&l.event)
- if err != nil {
- return fmt.Errorf("Failed to add event: ", err)
- }
-
- return nil
-
-}
-
-// handleEvent handles epoll event for listener
-func (l *listener) handleEvent(event *syscall.EpollEvent) error {
- // hang up
- if (event.Events & syscall.EPOLLHUP) == syscall.EPOLLHUP {
- err := l.close()
- if err != nil {
- return fmt.Errorf("Failed to close listener after hang up event: ", err)
- }
- return fmt.Errorf("Hang up: ", l.socket.filename)
- }
-
- // error
- if (event.Events & syscall.EPOLLERR) == syscall.EPOLLERR {
- err := l.close()
- if err != nil {
- return fmt.Errorf("Failed to close listener after receiving an error event: ", err)
- }
- return fmt.Errorf("Received error event on listener ", l.socket.filename)
- }
-
- // read message
- if (event.Events & syscall.EPOLLIN) == syscall.EPOLLIN {
- newFd, _, err := syscall.Accept(int(l.event.Fd))
- if err != nil {
- return fmt.Errorf("Accept: %s", err)
- }
-
- cc, err := l.socket.addControlChannel(newFd, nil)
- if err != nil {
- return fmt.Errorf("Failed to add control channel: %s", err)
- }
-
- err = cc.msgEnqHello()
- if err != nil {
- return fmt.Errorf("msgEnqHello: %s", err)
- }
-
- err = cc.sendMsg()
- if err != nil {
- return err
- }
-
- return nil
- }
-
- return fmt.Errorf("Unexpected event: ", event.Events)
-}
-
-// handleEvent handles epoll event for control channel
-func (cc *controlChannel) handleEvent(event *syscall.EpollEvent) error {
- var size int
- var err error
-
- // hang up
- if (event.Events & syscall.EPOLLHUP) == syscall.EPOLLHUP {
- // close cc, don't send msg
- err := cc.close(false, "")
- if err != nil {
- return fmt.Errorf("Failed to close control channel after hang up event: ", err)
- }
- return fmt.Errorf("Hang up: ", cc.i.GetName())
- }
-
- if (event.Events & syscall.EPOLLERR) == syscall.EPOLLERR {
- // close cc, don't send msg
- err := cc.close(false, "")
- if err != nil {
- return fmt.Errorf("Failed to close control channel after receiving an error event: ", err)
- }
- return fmt.Errorf("Received error event on control channel ", cc.i.GetName())
- }
-
- if (event.Events & syscall.EPOLLIN) == syscall.EPOLLIN {
- size, cc.controlLen, _, _, err = syscall.Recvmsg(int(cc.event.Fd), cc.data[:], cc.control[:], 0)
- if err != nil {
- return fmt.Errorf("recvmsg: %s", err)
- }
- if size != msgSize {
- return fmt.Errorf("invalid message size %d", size)
- }
-
- err = cc.parseMsg()
- if err != nil {
- return err
- }
-
- err = cc.sendMsg()
- if err != nil {
- return err
- }
-
- return nil
- }
-
- return fmt.Errorf("Unexpected event: ", event.Events)
-}
-
-// close closes the listener
-func (l *listener) close() error {
- err := l.socket.delEvent(&l.event)
- if err != nil {
- return fmt.Errorf("Failed to del event: ", err)
- }
- err = syscall.Close(int(l.event.Fd))
- if err != nil {
- return fmt.Errorf("Failed to close socket: ", err)
- }
- return nil
-}
-
-// AddListener adds a lisntener to the socket. The fd must describe a
-// UNIX domain socket already bound to a UNIX domain filename and
-// marked as listener
-func (socket *Socket) AddListener(fd int) (err error) {
- l := &listener{
- // we will need this to look up master interface by id
- socket: socket,
- }
-
- l.event = syscall.EpollEvent{
- Events: syscall.EPOLLIN | syscall.EPOLLERR | syscall.EPOLLHUP,
- Fd: int32(fd),
- }
- err = socket.addEvent(&l.event)
- if err != nil {
- return fmt.Errorf("Failed to add event: ", err)
- }
-
- socket.listener = l
-
- return nil
-}
-
-// addListener creates new UNIX domain socket, binds it to the address
-// and marks it as listener
-func (socket *Socket) addListener() (err error) {
- // create socket
- fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0)
- if err != nil {
- return fmt.Errorf("Failed to create UNIX domain socket")
- }
- usa := &syscall.SockaddrUnix{Name: socket.filename}
- // Bind to address and start listening
- err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_PASSCRED, 1)
- if err != nil {
- return fmt.Errorf("Failed to set socket option %s : %v", socket.filename, err)
- }
- err = syscall.Bind(fd, usa)
- if err != nil {
- return fmt.Errorf("Failed to bind socket %s : %v", socket.filename, err)
- }
- err = syscall.Listen(fd, syscall.SOMAXCONN)
- if err != nil {
- return fmt.Errorf("Failed to listen on socket %s : %v", socket.filename, err)
- }
-
- return socket.AddListener(fd)
-}
-
-// close closes a control channel, if the control channel is assigned an
-// interface, the interface is disconnected
-func (cc *controlChannel) close(sendMsg bool, str string) (err error) {
- if sendMsg == true {
- // first clear message queue so that the disconnect
- // message is the only message in queue
- cc.msgQueue = []controlMsg{}
- cc.msgEnqDisconnect(str)
-
- err = cc.sendMsg()
- if err != nil {
- return err
- }
- }
-
- err = cc.socket.delEvent(&cc.event)
- if err != nil {
- return fmt.Errorf("Failed to del event: ", err)
- }
-
- // remove referance form socket
- cc.socket.ccList.Remove(cc.listRef)
-
- if cc.i != nil {
- err = cc.i.disconnect()
- if err != nil {
- return fmt.Errorf("Interface Disconnect: ", err)
- }
- }
-
- return nil
-}
-
-//addControlChannel returns a new controlChannel and adds it to the socket
-func (socket *Socket) addControlChannel(fd int, i *Interface) (*controlChannel, error) {
- cc := &controlChannel{
- socket: socket,
- i: i,
- isConnected: false,
- }
-
- var err error
-
- cc.event = syscall.EpollEvent{
- Events: syscall.EPOLLIN | syscall.EPOLLERR | syscall.EPOLLHUP,
- Fd: int32(fd),
- }
- err = socket.addEvent(&cc.event)
- if err != nil {
- return nil, fmt.Errorf("Failed to add event: ", err)
- }
-
- cc.listRef = socket.ccList.PushBack(cc)
-
- return cc, nil
-}
-
-func (cc *controlChannel) msgEnqAck() (err error) {
- buf := new(bytes.Buffer)
- err = binary.Write(buf, binary.LittleEndian, msgTypeAck)
-
- msg := controlMsg{
- Buffer: buf,
- Fd: -1,
- }
-
- cc.msgQueue = append(cc.msgQueue, msg)
-
- return nil
-}
-
-func (cc *controlChannel) msgEnqHello() (err error) {
- hello := MsgHello{
- VersionMin: Version,
- VersionMax: Version,
- MaxRegion: 255,
- MaxRingM2S: 255,
- MaxRingS2M: 255,
- MaxLog2RingSize: 14,
- }
-
- copy(hello.Name[:], []byte(cc.socket.appName))
-
- buf := new(bytes.Buffer)
- err = binary.Write(buf, binary.LittleEndian, msgTypeHello)
- err = binary.Write(buf, binary.LittleEndian, hello)
-
- msg := controlMsg{
- Buffer: buf,
- Fd: -1,
- }
-
- cc.msgQueue = append(cc.msgQueue, msg)
-
- return nil
-}
-
-func (cc *controlChannel) parseHello() (err error) {
- var hello MsgHello
-
- buf := bytes.NewReader(cc.data[msgTypeSize:])
- err = binary.Read(buf, binary.LittleEndian, &hello)
- if err != nil {
- return
- }
-
- if hello.VersionMin > Version || hello.VersionMax < Version {
- return fmt.Errorf("Incompatible memif version")
- }
-
- cc.i.run = cc.i.args.MemoryConfig
-
- cc.i.run.NumQueuePairs = min16(cc.i.args.MemoryConfig.NumQueuePairs, hello.MaxRingS2M)
- cc.i.run.NumQueuePairs = min16(cc.i.args.MemoryConfig.NumQueuePairs, hello.MaxRingM2S)
- cc.i.run.Log2RingSize = min8(cc.i.args.MemoryConfig.Log2RingSize, hello.MaxLog2RingSize)
-
- cc.i.remoteName = string(hello.Name[:])
-
- return nil
-}
-
-func (cc *controlChannel) msgEnqInit() (err error) {
- init := MsgInit{
- Version: Version,
- Id: cc.i.args.Id,
- Mode: cc.i.args.Mode,
- }
-
- copy(init.Name[:], []byte(cc.socket.appName))
-
- buf := new(bytes.Buffer)
- err = binary.Write(buf, binary.LittleEndian, msgTypeInit)
- err = binary.Write(buf, binary.LittleEndian, init)
-
- msg := controlMsg{
- Buffer: buf,
- Fd: -1,
- }
-
- cc.msgQueue = append(cc.msgQueue, msg)
-
- return nil
-}
-
-func (cc *controlChannel) parseInit() (err error) {
- var init MsgInit
-
- buf := bytes.NewReader(cc.data[msgTypeSize:])
- err = binary.Read(buf, binary.LittleEndian, &init)
- if err != nil {
- return
- }
-
- if init.Version != Version {
- return fmt.Errorf("Incompatible memif driver version")
- }
-
- // find peer interface
- for elt := cc.socket.interfaceList.Front(); elt != nil; elt = elt.Next() {
- i, ok := elt.Value.(*Interface)
- if ok {
- if i.args.Id == init.Id && i.args.IsMaster && i.cc == nil {
- // verify secret
- if i.args.Secret != init.Secret {
- return fmt.Errorf("Invalid secret")
- }
- // interface is assigned to control channel
- i.cc = cc
- cc.i = i
- cc.i.run = cc.i.args.MemoryConfig
- cc.i.remoteName = string(init.Name[:])
-
- return nil
- }
- }
- }
-
- return fmt.Errorf("Invalid interface id")
-}
-
-func (cc *controlChannel) msgEnqAddRegion(regionIndex uint16) (err error) {
- if len(cc.i.regions) <= int(regionIndex) {
- return fmt.Errorf("Invalid region index")
- }
-
- addRegion := MsgAddRegion{
- Index: regionIndex,
- Size: cc.i.regions[regionIndex].size,
- }
-
- buf := new(bytes.Buffer)
- err = binary.Write(buf, binary.LittleEndian, msgTypeAddRegion)
- err = binary.Write(buf, binary.LittleEndian, addRegion)
-
- msg := controlMsg{
- Buffer: buf,
- Fd: cc.i.regions[regionIndex].fd,
- }
-
- cc.msgQueue = append(cc.msgQueue, msg)
-
- return nil
-}
-
-func (cc *controlChannel) parseAddRegion() (err error) {
- var addRegion MsgAddRegion
-
- buf := bytes.NewReader(cc.data[msgTypeSize:])
- err = binary.Read(buf, binary.LittleEndian, &addRegion)
- if err != nil {
- return
- }
-
- fd, err := cc.parseControlMsg()
- if err != nil {
- return fmt.Errorf("parseControlMsg: %s", err)
- }
-
- if addRegion.Index > 255 {
- return fmt.Errorf("Invalid memory region index")
- }
-
- region := memoryRegion{
- size: addRegion.Size,
- fd: fd,
- }
-
- cc.i.regions = append(cc.i.regions, region)
-
- return nil
-}
-
-func (cc *controlChannel) msgEnqAddRing(ringType ringType, ringIndex uint16) (err error) {
- var q Queue
- var flags uint16 = 0
-
- if ringType == ringTypeS2M {
- q = cc.i.txQueues[ringIndex]
- flags = msgAddRingFlagS2M
- } else {
- q = cc.i.rxQueues[ringIndex]
- }
-
- addRing := MsgAddRing{
- Index: ringIndex,
- Offset: uint32(q.ring.offset),
- Region: uint16(q.ring.region),
- RingSizeLog2: uint8(q.ring.log2Size),
- Flags: flags,
- PrivateHdrSize: 0,
- }
-
- buf := new(bytes.Buffer)
- err = binary.Write(buf, binary.LittleEndian, msgTypeAddRing)
- err = binary.Write(buf, binary.LittleEndian, addRing)
-
- msg := controlMsg{
- Buffer: buf,
- Fd: q.interruptFd,
- }
-
- cc.msgQueue = append(cc.msgQueue, msg)
-
- return nil
-}
-
-func (cc *controlChannel) parseAddRing() (err error) {
- var addRing MsgAddRing
-
- buf := bytes.NewReader(cc.data[msgTypeSize:])
- err = binary.Read(buf, binary.LittleEndian, &addRing)
- if err != nil {
- return
- }
-
- fd, err := cc.parseControlMsg()
- if err != nil {
- return err
- }
-
- if addRing.Index >= cc.i.run.NumQueuePairs {
- return fmt.Errorf("invalid ring index")
- }
-
- q := Queue{
- i: cc.i,
- interruptFd: fd,
- }
-
- if (addRing.Flags & msgAddRingFlagS2M) == msgAddRingFlagS2M {
- q.ring = newRing(int(addRing.Region), ringTypeS2M, int(addRing.Offset), int(addRing.RingSizeLog2))
- cc.i.rxQueues = append(cc.i.rxQueues, q)
- } else {
- q.ring = newRing(int(addRing.Region), ringTypeM2S, int(addRing.Offset), int(addRing.RingSizeLog2))
- cc.i.txQueues = append(cc.i.txQueues, q)
- }
-
- return nil
-}
-
-func (cc *controlChannel) msgEnqConnect() (err error) {
- var connect MsgConnect
- copy(connect.Name[:], []byte(cc.i.args.Name))
-
- buf := new(bytes.Buffer)
- err = binary.Write(buf, binary.LittleEndian, msgTypeConnect)
- err = binary.Write(buf, binary.LittleEndian, connect)
-
- msg := controlMsg{
- Buffer: buf,
- Fd: -1,
- }
-
- cc.msgQueue = append(cc.msgQueue, msg)
-
- return nil
-}
-
-func (cc *controlChannel) parseConnect() (err error) {
- var connect MsgConnect
-
- buf := bytes.NewReader(cc.data[msgTypeSize:])
- err = binary.Read(buf, binary.LittleEndian, &connect)
- if err != nil {
- return
- }
-
- cc.i.peerName = string(connect.Name[:])
-
- err = cc.i.connect()
- if err != nil {
- return err
- }
- cc.isConnected = true
-
- return nil
-}
-
-func (cc *controlChannel) msgEnqConnected() (err error) {
- var connected MsgConnected
- copy(connected.Name[:], []byte(cc.i.args.Name))
-
- buf := new(bytes.Buffer)
- err = binary.Write(buf, binary.LittleEndian, msgTypeConnected)
- err = binary.Write(buf, binary.LittleEndian, connected)
-
- msg := controlMsg{
- Buffer: buf,
- Fd: -1,
- }
-
- cc.msgQueue = append(cc.msgQueue, msg)
-
- return nil
-}
-
-func (cc *controlChannel) parseConnected() (err error) {
- var conn MsgConnected
-
- buf := bytes.NewReader(cc.data[msgTypeSize:])
- err = binary.Read(buf, binary.LittleEndian, &conn)
- if err != nil {
- return
- }
-
- cc.i.peerName = string(conn.Name[:])
-
- err = cc.i.connect()
- if err != nil {
- return err
- }
- cc.isConnected = true
-
- return nil
-}
-
-func (cc *controlChannel) msgEnqDisconnect(str string) (err error) {
- dc := MsgDisconnect{
- // not implemented
- Code: 0,
- }
- copy(dc.String[:], str)
-
- buf := new(bytes.Buffer)
- err = binary.Write(buf, binary.LittleEndian, msgTypeDisconnect)
- err = binary.Write(buf, binary.LittleEndian, dc)
-
- msg := controlMsg{
- Buffer: buf,
- Fd: -1,
- }
-
- cc.msgQueue = append(cc.msgQueue, msg)
-
- return nil
-}
-
-func (cc *controlChannel) parseDisconnect() (err error) {
- var dc MsgDisconnect
-
- buf := bytes.NewReader(cc.data[msgTypeSize:])
- err = binary.Read(buf, binary.LittleEndian, &dc)
- if err != nil {
- return
- }
-
- err = cc.close(false, string(dc.String[:]))
- if err != nil {
- return fmt.Errorf("Failed to disconnect control channel: ", err)
- }
-
- return nil
-}
-
-func (cc *controlChannel) parseMsg() error {
- var msgType msgType
- var err error
-
- buf := bytes.NewReader(cc.data[:])
- err = binary.Read(buf, binary.LittleEndian, &msgType)
-
- if msgType == msgTypeAck {
- return nil
- } else if msgType == msgTypeHello {
- // Configure
- err = cc.parseHello()
- if err != nil {
- goto error
- }
- // Initialize slave memif
- err = cc.i.initializeRegions()
- if err != nil {
- goto error
- }
- err = cc.i.initializeQueues()
- if err != nil {
- goto error
- }
- // Enqueue messages
- err = cc.msgEnqInit()
- if err != nil {
- goto error
- }
- for i := 0; i < len(cc.i.regions); i++ {
- err = cc.msgEnqAddRegion(uint16(i))
- if err != nil {
- goto error
- }
- }
- for i := 0; uint16(i) < cc.i.run.NumQueuePairs; i++ {
- err = cc.msgEnqAddRing(ringTypeS2M, uint16(i))
- if err != nil {
- goto error
- }
- }
- for i := 0; uint16(i) < cc.i.run.NumQueuePairs; i++ {
- err = cc.msgEnqAddRing(ringTypeM2S, uint16(i))
- if err != nil {
- goto error
- }
- }
- err = cc.msgEnqConnect()
- if err != nil {
- goto error
- }
- } else if msgType == msgTypeInit {
- err = cc.parseInit()
- if err != nil {
- goto error
- }
-
- err = cc.msgEnqAck()
- if err != nil {
- goto error
- }
- } else if msgType == msgTypeAddRegion {
- err = cc.parseAddRegion()
- if err != nil {
- goto error
- }
-
- err = cc.msgEnqAck()
- if err != nil {
- goto error
- }
- } else if msgType == msgTypeAddRing {
- err = cc.parseAddRing()
- if err != nil {
- goto error
- }
-
- err = cc.msgEnqAck()
- if err != nil {
- goto error
- }
- } else if msgType == msgTypeConnect {
- err = cc.parseConnect()
- if err != nil {
- goto error
- }
-
- err = cc.msgEnqConnected()
- if err != nil {
- goto error
- }
- } else if msgType == msgTypeConnected {
- err = cc.parseConnected()
- if err != nil {
- goto error
- }
- } else if msgType == msgTypeDisconnect {
- err = cc.parseDisconnect()
- if err != nil {
- goto error
- }
- } else {
- err = fmt.Errorf("unknown message %d", msgType)
- goto error
- }
-
- return nil
-
-error:
- err1 := cc.close(true, err.Error())
- if err1 != nil {
- return fmt.Errorf(err.Error(), ": Failed to close control channel: ", err1)
- }
-
- return err
-}
-
-// parseControlMsg parses control message and returns file descriptor
-// if any
-func (cc *controlChannel) parseControlMsg() (fd int, err error) {
- // Assert only called when we require FD
- fd = -1
-
- controlMsgs, err := syscall.ParseSocketControlMessage(cc.control[:cc.controlLen])
- if err != nil {
- return -1, fmt.Errorf("syscall.ParseSocketControlMessage: %s", err)
- }
-
- if len(controlMsgs) == 0 {
- return -1, fmt.Errorf("Missing control message")
- }
-
- for _, cmsg := range controlMsgs {
- if cmsg.Header.Level == syscall.SOL_SOCKET {
- if cmsg.Header.Type == syscall.SCM_RIGHTS {
- FDs, err := syscall.ParseUnixRights(&cmsg)
- if err != nil {
- return -1, fmt.Errorf("syscall.ParseUnixRights: %s", err)
- }
- if len(FDs) == 0 {
- continue
- }
- // Only expect single FD
- fd = FDs[0]
- }
- }
- }
-
- if fd == -1 {
- return -1, fmt.Errorf("Missing file descriptor")
- }
-
- return fd, nil
-}
diff --git a/extras/gomemif/memif/control_channel_unsafe.go b/extras/gomemif/memif/control_channel_unsafe.go
deleted file mode 100644
index 9e91297..0000000
--- a/extras/gomemif/memif/control_channel_unsafe.go
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 memif
-
-import (
- "fmt"
- "os"
- "syscall"
- "unsafe"
-)
-
-// sendMsg sends a control message from contorl channels message queue
-func (cc *controlChannel) sendMsg() (err error) {
- if len(cc.msgQueue) < 1 {
- return nil
- }
- // Get message buffer
- msg := cc.msgQueue[0]
- // Dequeue
- cc.msgQueue = cc.msgQueue[1:]
-
- iov := &syscall.Iovec{
- Base: &msg.Buffer.Bytes()[0],
- Len: msgSize,
- }
-
- msgh := syscall.Msghdr{
- Iov: iov,
- Iovlen: 1,
- }
-
- if msg.Fd > 0 {
- oob := syscall.UnixRights(msg.Fd)
- msgh.Control = &oob[0]
- msgh.Controllen = uint64(syscall.CmsgSpace(4))
- }
-
- _, _, errno := syscall.Syscall(syscall.SYS_SENDMSG, uintptr(cc.event.Fd), uintptr(unsafe.Pointer(&msgh)), uintptr(0))
- if errno != 0 {
- err = os.NewSyscallError("sendmsg", errno)
- return fmt.Errorf("SYS_SENDMSG: %s", errno)
- }
-
- return nil
-}
diff --git a/extras/gomemif/memif/interface.go b/extras/gomemif/memif/interface.go
deleted file mode 100644
index 4a45075..0000000
--- a/extras/gomemif/memif/interface.go
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 memif provides the implementation of shared memory interface (memif).
-//
-// Memif network interfaces communicate using UNIX domain socket. This socket
-// must be first created using NewSocket(). Then interfaces can be added
-// to this socket using NewInterface(). To start communication on each socket
-// socket.StartPolling() must be called. socket.StopPolling() will stop
-// the communication. When the interface changes link status Connected and
-// Disconencted callbacks set in Arguments for each interface are called
-// respectively. Once the interface is connected rx and tx queues can be
-// aquired using interface.GetRxQueue() and interface.GetTxQueue().
-// Packets can be transmitted by calling queue.ReadPacket() on rx queues and
-// queue.WritePacket() on tx queues. If the interface is disconnected
-// queue.ReadPacket() and queue.WritePacket() MUST not be called.
-//
-// Data transmission is backed by shared memory. The driver works in
-// promiscuous mode only.
-package memif
-
-import (
- "container/list"
- "fmt"
- "os"
- "syscall"
-)
-
-const (
- DefaultSocketFilename = "/run/vpp/memif.sock"
- DefaultNumQueuePairs = 1
- DefaultLog2RingSize = 10
- DefaultPacketBufferSize = 2048
-)
-
-const mfd_allow_sealing = 2
-const sys_memfd_create = 319
-const f_add_seals = 1033
-const f_seal_shrink = 0x0002
-
-const efd_nonblock = 04000
-
-// ConnectedFunc is a callback called when an interface is connected
-type ConnectedFunc func(i *Interface) error
-
-// DisconnectedFunc is a callback called when an interface is disconnected
-type DisconnectedFunc func(i *Interface) error
-
-type InterruptFunc func(i *Interface) error
-
-// MemoryConfig represents shared memory configuration
-type MemoryConfig struct {
- NumQueuePairs uint16 // number of queue pairs
- Log2RingSize uint8 // ring size as log2
- PacketBufferSize uint32 // size of single packet buffer
-}
-
-// Arguments represent interface configuration
-type Arguments struct {
- Id uint32 // Interface identifier unique across socket. Used to identify peer interface when connecting
- IsMaster bool // Interface role master/slave
- Mode interfaceMode
- Name string
- Secret [24]byte // optional parameter, secrets of the interfaces must match if they are to connect
- MemoryConfig MemoryConfig
- ConnectedFunc ConnectedFunc // callback called when interface changes status to connected
- DisconnectedFunc DisconnectedFunc // callback called when interface changes status to disconnected
- InterruptFunc InterruptFunc
- PrivateData interface{} // private data used by client program
- InterruptFd uint16
-}
-
-// memoryRegion represents a shared memory mapped file
-type memoryRegion struct {
- data []byte
- size uint64
- fd int
- packetBufferOffset uint32
-}
-
-// Queue represents rx or tx queue
-type Queue struct {
- ring *ring
- i *Interface
- lastHead uint16
- lastTail uint16
- interruptFd int
-}
-
-// Interface represents memif network interface
-type Interface struct {
- args Arguments
- run MemoryConfig
- privateData interface{}
- listRef *list.Element
- socket *Socket
- cc *controlChannel
- remoteName string
- peerName string
- regions []memoryRegion
- txQueues []Queue
- rxQueues []Queue
- onInterrupt InterruptFunc
-}
-
-// IsMaster returns true if the interfaces role is master, else returns false
-func (i *Interface) IsMaster() bool {
- return i.args.IsMaster
-}
-
-// GetRemoteName returns the name of the application on which the peer
-// interface exists
-func (i *Interface) GetRemoteName() string {
- return i.remoteName
-}
-
-// GetPeerName returns peer interfaces name
-func (i *Interface) GetPeerName() string {
- return i.peerName
-}
-
-// GetName returens interfaces name
-func (i *Interface) GetName() string {
- return i.args.Name
-}
-
-// GetMemoryConfig returns interfaces active memory config.
-// If interface is not connected the config is invalid.
-func (i *Interface) GetMemoryConfig() MemoryConfig {
- return i.run
-}
-
-// GetRxQueue returns an rx queue specified by queue index
-func (i *Interface) GetRxQueue(qid int) (*Queue, error) {
- if qid >= len(i.rxQueues) {
- return nil, fmt.Errorf("Invalid Queue index")
- }
- return &i.rxQueues[qid], nil
-}
-
-// GetRxQueue returns a tx queue specified by queue index
-func (i *Interface) GetTxQueue(qid int) (*Queue, error) {
- if qid >= len(i.txQueues) {
- return nil, fmt.Errorf("Invalid Queue index")
- }
- return &i.txQueues[qid], nil
-}
-
-// GetEventFd returns queues interrupt event fd
-func (q *Queue) GetEventFd() (int, error) {
- return q.interruptFd, nil
-}
-
-// GetFilename returns sockets filename
-func (socket *Socket) GetFilename() string {
- return socket.filename
-}
-
-// close closes the queue
-func (q *Queue) close() {
- syscall.Close(q.interruptFd)
-}
-
-// IsConnecting returns true if the interface is connecting
-func (i *Interface) IsConnecting() bool {
- if i.cc != nil {
- return true
- }
- return false
-}
-
-// IsConnected returns true if the interface is connected
-func (i *Interface) IsConnected() bool {
- if i.cc != nil && i.cc.isConnected {
- return true
- }
- return false
-}
-
-// Disconnect disconnects the interface
-func (i *Interface) Disconnect() (err error) {
- if i.cc != nil {
- // close control and disconenct interface
- return i.cc.close(true, "Interface disconnected")
- }
- return nil
-}
-
-// disconnect finalizes interface disconnection
-func (i *Interface) disconnect() (err error) {
- if i.cc == nil { // disconnected
- return nil
- }
-
- err = i.args.DisconnectedFunc(i)
- if err != nil {
- return fmt.Errorf("DisconnectedFunc: ", err)
- }
-
- for _, q := range i.txQueues {
- q.close()
- }
- i.txQueues = []Queue{}
-
- for _, q := range i.rxQueues {
- q.close()
- }
- i.rxQueues = []Queue{}
-
- // unmap regions
- for _, r := range i.regions {
- err = syscall.Munmap(r.data)
- if err != nil {
- return err
- }
- err = syscall.Close(r.fd)
- if err != nil {
- return err
- }
- }
- i.regions = nil
- i.cc = nil
-
- i.peerName = ""
- i.remoteName = ""
-
- return nil
-}
-
-// Delete deletes the interface
-func (i *Interface) Delete() (err error) {
- i.Disconnect()
-
- // remove referance on socket
- i.socket.interfaceList.Remove(i.listRef)
- i = nil
-
- return nil
-}
-
-// GetSocket returns the socket the interface belongs to
-func (i *Interface) GetSocket() *Socket {
- return i.socket
-}
-
-// GetPrivateDate returns interfaces private data
-func (i *Interface) GetPrivateData() interface{} {
- return i.args.PrivateData
-}
-
-// GetId returns interfaces id
-func (i *Interface) GetId() uint32 {
- return i.args.Id
-}
-
-// RoleToString returns 'Master' if isMaster os true, else returns 'Slave'
-func RoleToString(isMaster bool) string {
- if isMaster {
- return "Master"
- }
- return "Slave"
-}
-
-func memifPathIsAbstract(filename string) bool {
- return (filename[0] == '@')
-}
-
-// RequestConnection is used by slave interface to connect to a socket and
-// create a control channel
-func (i *Interface) RequestConnection() error {
- if i.IsMaster() {
- return fmt.Errorf("Only slave can request connection")
- }
- // create socket
- fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0)
- if err != nil {
- return fmt.Errorf("Failed to create UNIX domain socket: %v", err)
- }
- usa := &syscall.SockaddrUnix{Name: i.socket.filename}
-
- if memifPathIsAbstract(i.socket.GetFilename()) {
- usa.Name = "\000" + usa.Name[1:]
- }
- // Connect to listener socket
- err = syscall.Connect(fd, usa)
- if err != nil {
- return fmt.Errorf("Failed to connect socket %s : %v", i.socket.filename, err)
- }
-
- // Create control channel
- i.cc, err = i.socket.addControlChannel(fd, i)
- if err != nil {
- return fmt.Errorf("Failed to create control channel: %v", err)
- }
-
- return nil
-}
-
-// NewInterface returns a new memif network interface. When creating an interface
-// it's id must be unique across socket with the exception of loopback interface
-// in which case the id is the same but role differs
-func (socket *Socket) NewInterface(args *Arguments) (*Interface, error) {
- var err error
- // make sure the ID is unique on this socket
- for elt := socket.interfaceList.Front(); elt != nil; elt = elt.Next() {
- i, ok := elt.Value.(*Interface)
- if ok {
- if i.args.Id == args.Id && i.args.IsMaster == args.IsMaster {
- return nil, fmt.Errorf("Interface with id %u role %s already exists on this socket", args.Id, RoleToString(args.IsMaster))
- }
- }
- }
-
- // copy interface configuration
- i := Interface{
- args: *args,
- onInterrupt: args.InterruptFunc,
- }
- // set default values
- if i.args.MemoryConfig.NumQueuePairs == 0 {
- i.args.MemoryConfig.NumQueuePairs = DefaultNumQueuePairs
- }
- if i.args.MemoryConfig.Log2RingSize == 0 {
- i.args.MemoryConfig.Log2RingSize = DefaultLog2RingSize
- }
- if i.args.MemoryConfig.PacketBufferSize == 0 {
- i.args.MemoryConfig.PacketBufferSize = DefaultPacketBufferSize
- }
-
- i.socket = socket
-
- // append interface to the list
- i.listRef = socket.interfaceList.PushBack(&i)
-
- if i.args.IsMaster {
- if socket.listener == nil {
- err = socket.addListener()
- if err != nil {
- return nil, fmt.Errorf("Failed to create listener channel: %s", err)
- }
- }
- }
-
- return &i, nil
-}
-
-// eventFd returns an eventfd (SYS_EVENTFD2)
-func eventFd() (efd int, err error) {
- u_efd, _, errno := syscall.Syscall(syscall.SYS_EVENTFD2, uintptr(0), uintptr(efd_nonblock), 0)
- if errno != 0 {
- return -1, os.NewSyscallError("eventfd", errno)
- }
- return int(u_efd), nil
-}
-
-// addRegions creates and adds a new memory region to the interface (slave only)
-func (i *Interface) addRegion(hasPacketBuffers bool, hasRings bool) (err error) {
- var r memoryRegion
-
- if hasRings {
- r.packetBufferOffset = uint32((i.run.NumQueuePairs + i.run.NumQueuePairs) * (ringSize + descSize*(1<<i.run.Log2RingSize)))
- } else {
- r.packetBufferOffset = 0
- }
-
- if hasPacketBuffers {
- r.size = uint64(r.packetBufferOffset + i.run.PacketBufferSize*uint32(1<<i.run.Log2RingSize)*uint32(i.run.NumQueuePairs+i.run.NumQueuePairs))
- } else {
- r.size = uint64(r.packetBufferOffset)
- }
-
- r.fd, err = memfdCreate()
- if err != nil {
- return err
- }
-
- _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(r.fd), uintptr(f_add_seals), uintptr(f_seal_shrink))
- if errno != 0 {
- syscall.Close(r.fd)
- return fmt.Errorf("memfdCreate: %s", os.NewSyscallError("fcntl", errno))
- }
-
- err = syscall.Ftruncate(r.fd, int64(r.size))
- if err != nil {
- syscall.Close(r.fd)
- r.fd = -1
- return fmt.Errorf("memfdCreate: %s", err)
- }
-
- r.data, err = syscall.Mmap(r.fd, 0, int(r.size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
- if err != nil {
- return fmt.Errorf("addRegion: %s", err)
- }
-
- i.regions = append(i.regions, r)
-
- return nil
-}
-
-// initializeRegions initializes interfaces regions (slave only)
-func (i *Interface) initializeRegions() (err error) {
-
- err = i.addRegion(true, true)
- if err != nil {
- return fmt.Errorf("initializeRegions: %s", err)
- }
-
- return nil
-}
-
-// initializeQueues initializes interfaces queues (slave only)
-func (i *Interface) initializeQueues() (err error) {
- var q *Queue
- var desc descBuf
- var slot int
-
- desc = newDescBuf()
- desc.setFlags(0)
- desc.setRegion(0)
- desc.setLength(int(i.run.PacketBufferSize))
-
- for qid := 0; qid < int(i.run.NumQueuePairs); qid++ {
- /* TX */
- q = &Queue{
- ring: i.newRing(0, ringTypeS2M, qid),
- lastHead: 0,
- lastTail: 0,
- i: i,
- }
- q.ring.setCookie(cookie)
- q.ring.setFlags(1)
- q.interruptFd, err = eventFd()
- if err != nil {
- return err
- }
- i.socket.addInterrupt(q.interruptFd)
- q.putRing()
- i.txQueues = append(i.txQueues, *q)
-
- for j := 0; j < q.ring.size; j++ {
- slot = qid*q.ring.size + j
- desc.setOffset(int(i.regions[0].packetBufferOffset + uint32(slot)*i.run.PacketBufferSize))
- q.putDescBuf(slot, desc)
- }
- }
- for qid := 0; qid < int(i.run.NumQueuePairs); qid++ {
- /* RX */
- q = &Queue{
- ring: i.newRing(0, ringTypeM2S, qid),
- lastHead: 0,
- lastTail: 0,
- i: i,
- }
- q.ring.setCookie(cookie)
- if i.args.InterruptFunc == nil {
- q.ring.setFlags(1)
- } else {
- q.ring.setFlags(0)
- }
- q.interruptFd, err = eventFd()
- if err != nil {
- return err
- }
- i.args.InterruptFd = uint16(q.interruptFd)
- i.socket.addInterrupt(q.interruptFd)
- q.putRing()
- i.rxQueues = append(i.rxQueues, *q)
-
- for j := 0; j < q.ring.size; j++ {
- slot = qid*q.ring.size + j
- desc.setOffset(int(i.regions[0].packetBufferOffset + uint32(slot)*i.run.PacketBufferSize))
- q.putDescBuf(slot, desc)
- }
- }
-
- return nil
-}
-
-// connect finalizes interface connection
-func (i *Interface) connect() (err error) {
- for rid, _ := range i.regions {
- r := &i.regions[rid]
- if r.data == nil {
- r.data, err = syscall.Mmap(r.fd, 0, int(r.size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
- if err != nil {
- return fmt.Errorf("Mmap: %s", err)
- }
- }
- }
-
- for _, q := range i.txQueues {
- q.updateRing()
-
- if q.ring.getCookie() != cookie {
- return fmt.Errorf("Wrong cookie")
- }
-
- q.lastHead = 0
- q.lastTail = 0
- }
-
- for _, q := range i.rxQueues {
- q.updateRing()
-
- if q.ring.getCookie() != cookie {
- return fmt.Errorf("Wrong cookie")
- }
-
- q.lastHead = 0
- q.lastTail = 0
- }
-
- return i.args.ConnectedFunc(i)
-}
diff --git a/extras/gomemif/memif/interface_unsafe.go b/extras/gomemif/memif/interface_unsafe.go
deleted file mode 100644
index f5cbc2e..0000000
--- a/extras/gomemif/memif/interface_unsafe.go
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 memif
-
-import (
- "fmt"
- "os"
- "syscall"
- "unsafe"
-)
-
-// memfdCreate returns memory file file descriptor (memif.sys_memfd_create)
-func memfdCreate() (mfd int, err error) {
- p0, err := syscall.BytePtrFromString("memif_region_0")
- if err != nil {
- return -1, fmt.Errorf("memfdCreate: %s", err)
- }
-
- u_mfd, _, errno := syscall.Syscall(sys_memfd_create, uintptr(unsafe.Pointer(p0)), uintptr(mfd_allow_sealing), uintptr(0))
- if errno != 0 {
- return -1, fmt.Errorf("memfdCreate: %s", os.NewSyscallError("memfd_create", errno))
- }
-
- return int(u_mfd), nil
-}
diff --git a/extras/gomemif/memif/memif.go b/extras/gomemif/memif/memif.go
deleted file mode 100644
index bc1c560..0000000
--- a/extras/gomemif/memif/memif.go
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 memif
-
-import (
- "encoding/binary"
- "fmt"
- "syscall"
-)
-
-const cookie = 0x3E31F20
-
-// VersionMajor is memif protocols major version
-const VersionMajor = 2
-
-// VersionMinor is memif protocols minor version
-const VersionMinor = 0
-
-// Version is memif protocols version as uint16
-// (M-Major m-minor: MMMMMMMMmmmmmmmm)
-const Version = ((VersionMajor << 8) | VersionMinor)
-
-type msgType uint16
-
-const (
- msgTypeNone msgType = iota
- msgTypeAck
- msgTypeHello
- msgTypeInit
- msgTypeAddRegion
- msgTypeAddRing
- msgTypeConnect
- msgTypeConnected
- msgTypeDisconnect
-)
-
-type interfaceMode uint8
-
-const (
- InterfaceModeEthernet interfaceMode = iota
- InterfaceModeIp
- InterfaceModePuntInject
-)
-
-const msgSize = 128
-const msgTypeSize = 2
-
-const msgAddRingFlagS2M = (1 << 0)
-
-// Descriptor flags
-//
-// next buffer present
-const descFlagNext = (1 << 0)
-
-// Ring flags
-//
-// Interrupt
-const ringFlagInterrupt = 1
-
-func min16(a uint16, b uint16) uint16 {
- if a < b {
- return a
- }
- return b
-}
-
-func min8(a uint8, b uint8) uint8 {
- if a < b {
- return a
- }
- return b
-}
-
-type MsgHello struct {
- // app name
- Name [32]byte
- VersionMin uint16
- VersionMax uint16
- MaxRegion uint16
- MaxRingM2S uint16
- MaxRingS2M uint16
- MaxLog2RingSize uint8
-}
-
-type MsgInit struct {
- Version uint16
- Id uint32
- Mode interfaceMode
- Secret [24]byte
- // app name
- Name [32]byte
-}
-
-type MsgAddRegion struct {
- Index uint16
- Size uint64
-}
-
-type MsgAddRing struct {
- Flags uint16
- Index uint16
- Region uint16
- Offset uint32
- RingSizeLog2 uint8
- PrivateHdrSize uint16
-}
-
-type MsgConnect struct {
- // interface name
- Name [32]byte
-}
-
-type MsgConnected struct {
- // interface name
- Name [32]byte
-}
-
-type MsgDisconnect struct {
- Code uint32
- String [96]byte
-}
-
-/* DESCRIPTOR BEGIN */
-
-const descSize = 16
-
-// desc field offsets
-const descFlagsOffset = 0
-const descRegionOffset = 2
-const descLengthOffset = 4
-const descOffsetOffset = 8
-const descMetadataOffset = 12
-
-// descBuf represents a memif descriptor as array of bytes
-type descBuf []byte
-
-// newDescBuf returns new descriptor buffer
-func newDescBuf() descBuf {
- return make(descBuf, descSize)
-}
-
-// getDescBuff copies descriptor from shared memory to descBuf
-func (q *Queue) getDescBuf(slot int, db descBuf) {
- copy(db, q.i.regions[q.ring.region].data[q.ring.offset+ringSize+slot*descSize:])
-}
-
-// putDescBuf copies contents of descriptor buffer into shared memory
-func (q *Queue) putDescBuf(slot int, db descBuf) {
- copy(q.i.regions[q.ring.region].data[q.ring.offset+ringSize+slot*descSize:], db)
-}
-
-func (db descBuf) getFlags() int {
- return (int)(binary.LittleEndian.Uint16((db)[descFlagsOffset:]))
-}
-
-func (db descBuf) getRegion() int {
- return (int)(binary.LittleEndian.Uint16((db)[descRegionOffset:]))
-}
-
-func (db descBuf) getLength() int {
- return (int)(binary.LittleEndian.Uint32((db)[descLengthOffset:]))
-}
-
-func (db descBuf) getOffset() int {
- return (int)(binary.LittleEndian.Uint32((db)[descOffsetOffset:]))
-}
-
-func (db descBuf) getMetadata() int {
- return (int)(binary.LittleEndian.Uint32((db)[descMetadataOffset:]))
-}
-
-func (db descBuf) setFlags(val int) {
- binary.LittleEndian.PutUint16((db)[descFlagsOffset:], uint16(val))
-}
-
-func (db descBuf) setRegion(val int) {
- binary.LittleEndian.PutUint16((db)[descRegionOffset:], uint16(val))
-}
-
-func (db descBuf) setLength(val int) {
- binary.LittleEndian.PutUint32((db)[descLengthOffset:], uint32(val))
-}
-
-func (db descBuf) setOffset(val int) {
- binary.LittleEndian.PutUint32((db)[descOffsetOffset:], uint32(val))
-}
-
-func (db descBuf) setMetadata(val int) {
- binary.LittleEndian.PutUint32((db)[descMetadataOffset:], uint32(val))
-}
-
-/* DESCRIPTOR END */
-
-/* RING BEGIN */
-
-type ringType uint8
-
-const (
- ringTypeS2M ringType = iota
- ringTypeM2S
-)
-
-const ringSize = 128
-
-// ring field offsets
-const ringCookieOffset = 0
-const ringFlagsOffset = 4
-const ringHeadOffset = 6
-const ringTailOffset = 64
-
-// ringBuf represents a memif ring as array of bytes
-type ringBuf []byte
-
-type ring struct {
- ringType ringType
- size int
- log2Size int
- region int
- rb ringBuf
- offset int
-}
-
-// newRing returns new memif ring based on data received in msgAddRing (master only)
-func newRing(regionIndex int, ringType ringType, ringOffset int, log2RingSize int) *ring {
- r := &ring{
- ringType: ringType,
- size: (1 << log2RingSize),
- log2Size: log2RingSize,
- rb: make(ringBuf, ringSize),
- offset: ringOffset,
- }
-
- return r
-}
-
-// newRing returns a new memif ring
-func (i *Interface) newRing(regionIndex int, ringType ringType, ringIndex int) *ring {
- r := &ring{
- ringType: ringType,
- size: (1 << i.run.Log2RingSize),
- log2Size: int(i.run.Log2RingSize),
- rb: make(ringBuf, ringSize),
- }
-
- rSize := ringSize + descSize*r.size
- if r.ringType == ringTypeS2M {
- r.offset = 0
- } else {
- r.offset = int(i.run.NumQueuePairs) * rSize
- }
- r.offset += ringIndex * rSize
-
- return r
-}
-
-// putRing put the ring to the shared memory
-func (q *Queue) putRing() {
- copy(q.i.regions[q.ring.region].data[q.ring.offset:], q.ring.rb)
-}
-
-// updateRing updates ring with data from shared memory
-func (q *Queue) updateRing() {
- copy(q.ring.rb, q.i.regions[q.ring.region].data[q.ring.offset:])
-}
-
-func (r *ring) getCookie() int {
- return (int)(binary.LittleEndian.Uint32((r.rb)[ringCookieOffset:]))
-}
-
-// getFlags returns the flags value from ring buffer
-// Use Queue.getFlags in fast-path to avoid updating the whole ring.
-func (r *ring) getFlags() int {
- return (int)(binary.LittleEndian.Uint16((r.rb)[ringFlagsOffset:]))
-}
-
-// getHead returns the head pointer value from ring buffer.
-// Use readHead in fast-path to avoid updating the whole ring.
-func (r *ring) getHead() int {
- return (int)(binary.LittleEndian.Uint16((r.rb)[ringHeadOffset:]))
-}
-
-// getTail returns the tail pointer value from ring buffer.
-// Use readTail in fast-path to avoid updating the whole ring.
-func (r *ring) getTail() int {
- return (int)(binary.LittleEndian.Uint16((r.rb)[ringTailOffset:]))
-}
-
-func (r *ring) setCookie(val int) {
- binary.LittleEndian.PutUint32((r.rb)[ringCookieOffset:], uint32(val))
-}
-
-func (r *ring) setFlags(val int) {
- binary.LittleEndian.PutUint16((r.rb)[ringFlagsOffset:], uint16(val))
-}
-
-// setHead set the head pointer value int the ring buffer.
-// Use writeHead in fast-path to avoid putting the whole ring into shared memory.
-func (r *ring) setHead(val int) {
- binary.LittleEndian.PutUint16((r.rb)[ringHeadOffset:], uint16(val))
-}
-
-// setTail set the tail pointer value int the ring buffer.
-// Use writeTail in fast-path to avoid putting the whole ring into shared memory.
-func (r *ring) setTail(val int) {
- binary.LittleEndian.PutUint16((r.rb)[ringTailOffset:], uint16(val))
-}
-
-/* RING END */
-
-// isInterrupt returns true if the queue is in interrupt mode
-func (q *Queue) isInterrupt() bool {
- return (q.getFlags() & ringFlagInterrupt) == 0
-}
-
-// interrupt performs an interrupt if the queue is in interrupt mode
-func (q *Queue) interrupt() error {
- if q.isInterrupt() {
- buf := make([]byte, 8)
- binary.PutUvarint(buf, 1)
- n, err := syscall.Write(q.interruptFd, buf[:])
- if err != nil {
- return err
- }
- if n != 8 {
- return fmt.Errorf("Faild to write to eventfd")
- }
- }
-
- return nil
-}
diff --git a/extras/gomemif/memif/memif_unsafe.go b/extras/gomemif/memif/memif_unsafe.go
deleted file mode 100644
index 4469d26..0000000
--- a/extras/gomemif/memif/memif_unsafe.go
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 memif
-
-import (
- "unsafe"
-)
-
-// readHead reads ring head directly form the shared memory
-func (q *Queue) readHead() (head int) {
- return (int)(*(*uint16)(unsafe.Pointer(&q.i.regions[q.ring.region].data[q.ring.offset+ringHeadOffset])))
- // return atomicload16(&q.i.regions[q.region].data[q.offset + descHeadOffset])
-}
-
-// readTail reads ring tail directly form the shared memory
-func (q *Queue) readTail() (tail int) {
- return (int)(*(*uint16)(unsafe.Pointer(&q.i.regions[q.ring.region].data[q.ring.offset+ringTailOffset])))
- // return atomicload16(&q.i.regions[q.region].data[q.offset + descTailOffset])
-}
-
-// writeHead writes ring head directly to the shared memory
-func (q *Queue) writeHead(value int) {
- *(*uint16)(unsafe.Pointer(&q.i.regions[q.ring.region].data[q.ring.offset+ringHeadOffset])) = *(*uint16)(unsafe.Pointer(&value))
- //atomicstore16(&q.i.regions[q.region].data[q.offset + descHeadOffset], value)
-}
-
-// writeTail writes ring tail directly to the shared memory
-func (q *Queue) writeTail(value int) {
- *(*uint16)(unsafe.Pointer(&q.i.regions[q.ring.region].data[q.ring.offset+ringTailOffset])) = *(*uint16)(unsafe.Pointer(&value))
- //atomicstore16(&q.i.regions[q.region].data[q.offset + descTailOffset], value)
-}
-
-func (q *Queue) setDescLength(slot int, length int) {
- *(*uint16)(unsafe.Pointer(&q.i.regions[q.ring.region].data[q.ring.offset+ringSize+slot*descSize+descLengthOffset])) = *(*uint16)(unsafe.Pointer(&length))
-}
-
-// getFlags reads ring flags directly from the shared memory
-func (q *Queue) getFlags() int {
- return (int)(*(*uint16)(unsafe.Pointer(&q.i.regions[q.ring.region].data[q.ring.offset+ringFlagsOffset])))
-}
diff --git a/extras/gomemif/memif/packet_reader.go b/extras/gomemif/memif/packet_reader.go
deleted file mode 100644
index 58338f6..0000000
--- a/extras/gomemif/memif/packet_reader.go
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 memif
-
-import "fmt"
-
-// ReadPacket reads one packet form the shared memory and
-// returns the number of bytes read
-func (q *Queue) ReadPacket(pkt []byte) (int, error) {
- var mask int = q.ring.size - 1
- var slot int
- var lastSlot int
- var length int
- var offset int
- var pktOffset int = 0
- var nSlots uint16
- var desc descBuf = newDescBuf()
-
- if q.i.args.IsMaster {
- slot = int(q.lastHead)
- lastSlot = q.readHead()
- } else {
- slot = int(q.lastTail)
- lastSlot = q.readTail()
- }
-
- nSlots = uint16(lastSlot - slot)
- if nSlots == 0 {
- goto refill
- }
-
- // copy descriptor from shm
- q.getDescBuf(slot&mask, desc)
- length = desc.getLength()
- offset = desc.getOffset()
-
- copy(pkt[:], q.i.regions[desc.getRegion()].data[offset:offset+length])
- pktOffset += length
-
- slot++
- nSlots--
-
- for (desc.getFlags() & descFlagNext) == descFlagNext {
- if nSlots == 0 {
- return 0, fmt.Errorf("Incomplete chained buffer, may suggest peer error.")
- }
-
- q.getDescBuf(slot&mask, desc)
- length = desc.getLength()
- offset = desc.getOffset()
-
- copy(pkt[pktOffset:], q.i.regions[desc.getRegion()].data[offset:offset+length])
- pktOffset += length
-
- slot++
- nSlots--
- }
-
-refill:
- if q.i.args.IsMaster {
- q.lastHead = uint16(slot)
- q.writeTail(slot)
- } else {
- q.lastTail = uint16(slot)
-
- head := q.readHead()
-
- for nSlots := uint16(q.ring.size - head + int(q.lastTail)); nSlots > 0; nSlots-- {
- q.setDescLength(head&mask, int(q.i.run.PacketBufferSize))
- head++
- }
- q.writeHead(head)
- }
-
- return pktOffset, nil
-}
diff --git a/extras/gomemif/memif/packet_writer.go b/extras/gomemif/memif/packet_writer.go
deleted file mode 100644
index 702044f..0000000
--- a/extras/gomemif/memif/packet_writer.go
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *------------------------------------------------------------------
- * 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 memif
-
-// WritePacket writes one packet to the shared memory and
-// returns the number of bytes written
-func (q *Queue) WritePacket(pkt []byte) int {
- var mask int = q.ring.size - 1
- var slot int
- var nFree uint16
- var packetBufferSize int = int(q.i.run.PacketBufferSize)
-
- if q.i.args.IsMaster {
- slot = q.readTail()
- nFree = uint16(q.readHead() - slot)
- } else {
- slot = q.readHead()
- nFree = uint16(q.ring.size - slot + q.readTail())
- }
-
- if nFree == 0 {
- q.interrupt()
- return 0
- }
-
- // copy descriptor from shm
- desc := newDescBuf()
- q.getDescBuf(slot&mask, desc)
- // reset flags
- desc.setFlags(0)
- // reset length
- if q.i.args.IsMaster {
- packetBufferSize = desc.getLength()
- }
- desc.setLength(0)
- offset := desc.getOffset()
-
- // write packet into memif buffer
- n := copy(q.i.regions[desc.getRegion()].data[offset:offset+packetBufferSize], pkt[:])
- desc.setLength(n)
- for n < len(pkt) {
- nFree--
- if nFree == 0 {
- q.interrupt()
- return 0
- }
- desc.setFlags(descFlagNext)
- q.putDescBuf(slot&mask, desc)
- slot++
-
- // copy descriptor from shm
- q.getDescBuf(slot&mask, desc)
- // reset flags
- desc.setFlags(0)
- // reset length
- if q.i.args.IsMaster {
- packetBufferSize = desc.getLength()
- }
- desc.setLength(0)
- offset := desc.getOffset()
-
- tmp := copy(q.i.regions[desc.getRegion()].data[offset:offset+packetBufferSize], pkt[:])
- desc.setLength(tmp)
- n += tmp
- }
-
- // copy descriptor to shm
- q.putDescBuf(slot&mask, desc)
- slot++
-
- if q.i.args.IsMaster {
- q.writeTail(slot)
- } else {
- q.writeHead(slot)
- }
-
- q.interrupt()
-
- return n
-}
diff --git a/extras/gomemif/migrated.txt b/extras/gomemif/migrated.txt
new file mode 100644
index 0000000..abe913a
--- /dev/null
+++ b/extras/gomemif/migrated.txt
@@ -0,0 +1 @@
+Gomemif has been migrated to GoVPP repository https://github.com/FDio/govpp
\ No newline at end of file