gomemif: migrate to govpp repository
Type: make Signed-off-by: Matus Halaj <mhalaj@cisco.com> Change-Id: I1d48c7e44fdf23438132996fd3288b29da1fe36e
This commit is contained in:
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
|
Loading…
x
Reference in New Issue
Block a user