summaryrefslogtreecommitdiffstats
path: root/extras/gomemif/memif/memif.go
diff options
context:
space:
mode:
Diffstat (limited to 'extras/gomemif/memif/memif.go')
-rw-r--r--extras/gomemif/memif/memif.go345
1 files changed, 345 insertions, 0 deletions
diff --git a/extras/gomemif/memif/memif.go b/extras/gomemif/memif/memif.go
new file mode 100644
index 00000000000..1a7857de03e
--- /dev/null
+++ b/extras/gomemif/memif/memif.go
@@ -0,0 +1,345 @@
+/*
+ *------------------------------------------------------------------
+ * 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
+}