aboutsummaryrefslogtreecommitdiffstats
path: root/extras/gomemif/memif/interface.go
diff options
context:
space:
mode:
Diffstat (limited to 'extras/gomemif/memif/interface.go')
-rw-r--r--extras/gomemif/memif/interface.go507
1 files changed, 0 insertions, 507 deletions
diff --git a/extras/gomemif/memif/interface.go b/extras/gomemif/memif/interface.go
deleted file mode 100644
index a571deb43c9..00000000000
--- a/extras/gomemif/memif/interface.go
+++ /dev/null
@@ -1,507 +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
-
-// 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
- 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
- PrivateData interface{} // private data used by client program
-}
-
-// 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
-}
-
-// 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"
-}
-
-// 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}
-
- // 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,
- }
- // 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
- }
- 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)
- q.ring.setFlags(1)
- q.interruptFd, err = eventFd()
- if err != nil {
- return err
- }
- 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)
-}