summaryrefslogtreecommitdiffstats
path: root/extras/libmemif/packethandle.go
diff options
context:
space:
mode:
Diffstat (limited to 'extras/libmemif/packethandle.go')
-rw-r--r--extras/libmemif/packethandle.go150
1 files changed, 150 insertions, 0 deletions
diff --git a/extras/libmemif/packethandle.go b/extras/libmemif/packethandle.go
new file mode 100644
index 0000000..83bf90a
--- /dev/null
+++ b/extras/libmemif/packethandle.go
@@ -0,0 +1,150 @@
+// Copyright (c) 2017 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 libmemif
+
+import (
+ "github.com/google/gopacket"
+ "time"
+ "sync"
+ "io"
+)
+
+type memoizedPacket struct {
+ data RawPacketData
+ ci gopacket.CaptureInfo
+}
+
+type MemifPacketHandle struct {
+ memif *Memif
+ queueId uint8
+ rxCount uint16
+
+ // Used for caching packets when larger rxburst is called
+ packetQueue []*memoizedPacket
+
+ // Used for synchronization of read/write calls
+ readMu sync.Mutex
+ writeMu sync.Mutex
+ closeMu sync.Mutex
+ stop bool
+}
+
+// Create new GoPacket packet handle from libmemif queue. rxCount determines how many packets will be read
+// at once, minimum value is 1
+func (memif *Memif) NewPacketHandle(queueId uint8, rxCount uint16) *MemifPacketHandle {
+ if rxCount == 0 {
+ rxCount = 1
+ }
+
+ return &MemifPacketHandle{
+ memif: memif,
+ queueId: queueId,
+ rxCount: rxCount,
+ }
+}
+
+// Reads packet data from memif in bursts, based on previously configured rxCount parameterer. Then caches the
+// resulting packets and returns them 1 by 1 from this method until queue is empty then tries to call new rx burst
+// to read more data. If no data is returned, io.EOF error is thrown and caller should stop reading.
+func (handle *MemifPacketHandle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
+ handle.readMu.Lock()
+ defer handle.readMu.Unlock()
+
+ if handle.stop {
+ err = io.EOF
+ return
+ }
+
+ queueLen := len(handle.packetQueue)
+
+ if queueLen == 0 {
+ packets, burstErr := handle.memif.RxBurst(handle.queueId, handle.rxCount)
+ packetsLen := len(packets)
+
+ if burstErr != nil {
+ err = burstErr
+ return
+ }
+
+ if packetsLen == 0 {
+ err = io.EOF
+ return
+ }
+
+ handle.packetQueue = make([]*memoizedPacket, packetsLen)
+
+ for i, packet := range packets {
+ packetLen := len(packet)
+
+ handle.packetQueue[i] = &memoizedPacket{
+ data: []byte(packet),
+ ci: gopacket.CaptureInfo{
+ Timestamp: time.Now(),
+ CaptureLength: packetLen,
+ Length: packetLen,
+ },
+ }
+ }
+ }
+
+ packet := handle.packetQueue[0]
+ handle.packetQueue = handle.packetQueue[1:]
+ data = packet.data
+ ci = packet.ci
+
+ return
+}
+
+// Writes packet data to memif in burst of 1 packet. In case no packet is sent, this method throws io.EOF error and
+// called should stop trying to write packets.
+func (handle *MemifPacketHandle) WritePacketData(data []byte) (err error) {
+ handle.writeMu.Lock()
+ defer handle.writeMu.Unlock()
+
+ if handle.stop {
+ err = io.EOF
+ return
+ }
+
+ count, err := handle.memif.TxBurst(handle.queueId, []RawPacketData{data})
+
+ if err != nil {
+ return
+ }
+
+ if count == 0 {
+ err = io.EOF
+ }
+
+ return
+}
+
+// Waits for all read and write operations to finish and then prevents more from occurring. Handle can be closed only
+// once and then can never be opened again.
+func (handle *MemifPacketHandle) Close() {
+ handle.closeMu.Lock()
+ defer handle.closeMu.Unlock()
+
+ // wait for packet reader to stop
+ handle.readMu.Lock()
+ defer handle.readMu.Unlock()
+
+ // wait for packet writer to stop
+ handle.writeMu.Lock()
+ defer handle.writeMu.Unlock()
+
+ // stop reading and writing
+ handle.stop = true
+}