Update libmemif
[govpp.git] / extras / libmemif / packethandle.go
1 // Copyright (c) 2017 Cisco and/or its affiliates.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package libmemif
16
17 import (
18         "github.com/google/gopacket"
19         "io"
20         "sync"
21         "time"
22 )
23
24 type memoizedPacket struct {
25         data RawPacketData
26         ci   gopacket.CaptureInfo
27 }
28
29 type MemifPacketHandle struct {
30         memif   *Memif
31         queueId uint8
32         rxCount uint16
33
34         // Used for caching packets when larger rxburst is called
35         packetQueue []*memoizedPacket
36
37         // Used for synchronization of read/write calls
38         readMu  sync.Mutex
39         writeMu sync.Mutex
40         closeMu sync.Mutex
41         stop    bool
42 }
43
44 // Create new GoPacket packet handle from libmemif queue. rxCount determines how many packets will be read
45 // at once, minimum value is 1
46 func (memif *Memif) NewPacketHandle(queueId uint8, rxCount uint16) *MemifPacketHandle {
47         if rxCount == 0 {
48                 rxCount = 1
49         }
50
51         return &MemifPacketHandle{
52                 memif:   memif,
53                 queueId: queueId,
54                 rxCount: rxCount,
55         }
56 }
57
58 // Reads packet data from memif in bursts, based on previously configured rxCount parameter. Then caches the
59 // resulting packets and returns them 1 by 1 from this method until queue is empty then tries to call new rx burst
60 // to read more data. If no data is returned, io.EOF error is thrown and caller should stop reading.
61 func (handle *MemifPacketHandle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
62         handle.readMu.Lock()
63         defer handle.readMu.Unlock()
64
65         if handle.stop {
66                 err = io.EOF
67                 return
68         }
69
70         queueLen := len(handle.packetQueue)
71
72         if queueLen == 0 {
73                 packets, burstErr := handle.memif.RxBurst(handle.queueId, handle.rxCount)
74                 packetsLen := len(packets)
75
76                 if burstErr != nil {
77                         err = burstErr
78                         return
79                 }
80
81                 if packetsLen == 0 {
82                         err = io.EOF
83                         return
84                 }
85
86                 handle.packetQueue = make([]*memoizedPacket, packetsLen)
87
88                 for i, packet := range packets {
89                         packetLen := len(packet)
90
91                         handle.packetQueue[i] = &memoizedPacket{
92                                 data: []byte(packet),
93                                 ci: gopacket.CaptureInfo{
94                                         Timestamp:     time.Now(),
95                                         CaptureLength: packetLen,
96                                         Length:        packetLen,
97                                 },
98                         }
99                 }
100         }
101
102         packet := handle.packetQueue[0]
103         handle.packetQueue = handle.packetQueue[1:]
104         data = packet.data
105         ci = packet.ci
106
107         return
108 }
109
110 // Writes packet data to memif in burst of 1 packet. In case no packet is sent, this method throws io.EOF error and
111 // called should stop trying to write packets.
112 func (handle *MemifPacketHandle) WritePacketData(data []byte) (err error) {
113         handle.writeMu.Lock()
114         defer handle.writeMu.Unlock()
115
116         if handle.stop {
117                 err = io.EOF
118                 return
119         }
120
121         count, err := handle.memif.TxBurst(handle.queueId, []RawPacketData{data})
122
123         if err != nil {
124                 return
125         }
126
127         if count == 0 {
128                 err = io.EOF
129         }
130
131         return
132 }
133
134 // Waits for all read and write operations to finish and then prevents more from occurring. Handle can be closed only
135 // once and then can never be opened again.
136 func (handle *MemifPacketHandle) Close() {
137         handle.closeMu.Lock()
138         defer handle.closeMu.Unlock()
139
140         // wait for packet reader to stop
141         handle.readMu.Lock()
142         defer handle.readMu.Unlock()
143
144         // wait for packet writer to stop
145         handle.writeMu.Lock()
146         defer handle.writeMu.Unlock()
147
148         // stop reading and writing
149         handle.stop = true
150 }