gomemif: migrate to govpp repository
Type: make Signed-off-by: Matus Halaj <mhalaj@cisco.com> Change-Id: I1d48c7e44fdf23438132996fd3288b29da1fe36e
This commit is contained in:
Matus Halaj
committed by
Dave Wallace
parent
70892fcada
commit
af36e96d07
@ -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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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"
|
|
||||||
)
|
|
@ -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"
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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",],
|
|
||||||
)
|
|
File diff suppressed because it is too large
Load Diff
@ -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
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -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
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -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])))
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
1
extras/gomemif/migrated.txt
Normal file
1
extras/gomemif/migrated.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Gomemif has been migrated to GoVPP repository https://github.com/FDio/govpp
|
Reference in New Issue
Block a user