blob: bc1c560862f72dac4aacc617eff5680c37c9f34f [file] [log] [blame]
Jakub Grajciar07363a42020-04-02 10:02:17 +02001/*
2 *------------------------------------------------------------------
3 * Copyright (c) 2020 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
16 */
17
18package memif
19
20import (
21 "encoding/binary"
22 "fmt"
23 "syscall"
24)
25
26const cookie = 0x3E31F20
27
28// VersionMajor is memif protocols major version
29const VersionMajor = 2
30
31// VersionMinor is memif protocols minor version
32const VersionMinor = 0
33
34// Version is memif protocols version as uint16
35// (M-Major m-minor: MMMMMMMMmmmmmmmm)
36const Version = ((VersionMajor << 8) | VersionMinor)
37
38type msgType uint16
39
40const (
41 msgTypeNone msgType = iota
42 msgTypeAck
43 msgTypeHello
44 msgTypeInit
45 msgTypeAddRegion
46 msgTypeAddRing
47 msgTypeConnect
48 msgTypeConnected
49 msgTypeDisconnect
50)
51
52type interfaceMode uint8
53
54const (
Nathan Skrzypczak176373c2021-05-07 19:39:07 +020055 InterfaceModeEthernet interfaceMode = iota
56 InterfaceModeIp
57 InterfaceModePuntInject
Jakub Grajciar07363a42020-04-02 10:02:17 +020058)
59
60const msgSize = 128
61const msgTypeSize = 2
62
63const msgAddRingFlagS2M = (1 << 0)
64
65// Descriptor flags
66//
67// next buffer present
68const descFlagNext = (1 << 0)
69
70// Ring flags
71//
72// Interrupt
73const ringFlagInterrupt = 1
74
75func min16(a uint16, b uint16) uint16 {
76 if a < b {
77 return a
78 }
79 return b
80}
81
82func min8(a uint8, b uint8) uint8 {
83 if a < b {
84 return a
85 }
86 return b
87}
88
89type MsgHello struct {
90 // app name
91 Name [32]byte
92 VersionMin uint16
93 VersionMax uint16
94 MaxRegion uint16
95 MaxRingM2S uint16
96 MaxRingS2M uint16
97 MaxLog2RingSize uint8
98}
99
100type MsgInit struct {
101 Version uint16
102 Id uint32
103 Mode interfaceMode
104 Secret [24]byte
105 // app name
106 Name [32]byte
107}
108
109type MsgAddRegion struct {
110 Index uint16
111 Size uint64
112}
113
114type MsgAddRing struct {
115 Flags uint16
116 Index uint16
117 Region uint16
118 Offset uint32
119 RingSizeLog2 uint8
120 PrivateHdrSize uint16
121}
122
123type MsgConnect struct {
124 // interface name
125 Name [32]byte
126}
127
128type MsgConnected struct {
129 // interface name
130 Name [32]byte
131}
132
133type MsgDisconnect struct {
134 Code uint32
135 String [96]byte
136}
137
138/* DESCRIPTOR BEGIN */
139
140const descSize = 16
141
142// desc field offsets
143const descFlagsOffset = 0
144const descRegionOffset = 2
145const descLengthOffset = 4
146const descOffsetOffset = 8
147const descMetadataOffset = 12
148
149// descBuf represents a memif descriptor as array of bytes
150type descBuf []byte
151
152// newDescBuf returns new descriptor buffer
153func newDescBuf() descBuf {
154 return make(descBuf, descSize)
155}
156
157// getDescBuff copies descriptor from shared memory to descBuf
158func (q *Queue) getDescBuf(slot int, db descBuf) {
159 copy(db, q.i.regions[q.ring.region].data[q.ring.offset+ringSize+slot*descSize:])
160}
161
162// putDescBuf copies contents of descriptor buffer into shared memory
163func (q *Queue) putDescBuf(slot int, db descBuf) {
164 copy(q.i.regions[q.ring.region].data[q.ring.offset+ringSize+slot*descSize:], db)
165}
166
167func (db descBuf) getFlags() int {
168 return (int)(binary.LittleEndian.Uint16((db)[descFlagsOffset:]))
169}
170
171func (db descBuf) getRegion() int {
172 return (int)(binary.LittleEndian.Uint16((db)[descRegionOffset:]))
173}
174
175func (db descBuf) getLength() int {
176 return (int)(binary.LittleEndian.Uint32((db)[descLengthOffset:]))
177}
178
179func (db descBuf) getOffset() int {
180 return (int)(binary.LittleEndian.Uint32((db)[descOffsetOffset:]))
181}
182
183func (db descBuf) getMetadata() int {
184 return (int)(binary.LittleEndian.Uint32((db)[descMetadataOffset:]))
185}
186
187func (db descBuf) setFlags(val int) {
188 binary.LittleEndian.PutUint16((db)[descFlagsOffset:], uint16(val))
189}
190
191func (db descBuf) setRegion(val int) {
192 binary.LittleEndian.PutUint16((db)[descRegionOffset:], uint16(val))
193}
194
195func (db descBuf) setLength(val int) {
196 binary.LittleEndian.PutUint32((db)[descLengthOffset:], uint32(val))
197}
198
199func (db descBuf) setOffset(val int) {
200 binary.LittleEndian.PutUint32((db)[descOffsetOffset:], uint32(val))
201}
202
203func (db descBuf) setMetadata(val int) {
204 binary.LittleEndian.PutUint32((db)[descMetadataOffset:], uint32(val))
205}
206
207/* DESCRIPTOR END */
208
209/* RING BEGIN */
210
211type ringType uint8
212
213const (
214 ringTypeS2M ringType = iota
215 ringTypeM2S
216)
217
218const ringSize = 128
219
220// ring field offsets
221const ringCookieOffset = 0
222const ringFlagsOffset = 4
223const ringHeadOffset = 6
224const ringTailOffset = 64
225
226// ringBuf represents a memif ring as array of bytes
227type ringBuf []byte
228
229type ring struct {
230 ringType ringType
231 size int
232 log2Size int
233 region int
234 rb ringBuf
235 offset int
236}
237
238// newRing returns new memif ring based on data received in msgAddRing (master only)
239func newRing(regionIndex int, ringType ringType, ringOffset int, log2RingSize int) *ring {
240 r := &ring{
241 ringType: ringType,
242 size: (1 << log2RingSize),
243 log2Size: log2RingSize,
244 rb: make(ringBuf, ringSize),
245 offset: ringOffset,
246 }
247
248 return r
249}
250
251// newRing returns a new memif ring
252func (i *Interface) newRing(regionIndex int, ringType ringType, ringIndex int) *ring {
253 r := &ring{
254 ringType: ringType,
255 size: (1 << i.run.Log2RingSize),
256 log2Size: int(i.run.Log2RingSize),
257 rb: make(ringBuf, ringSize),
258 }
259
260 rSize := ringSize + descSize*r.size
261 if r.ringType == ringTypeS2M {
262 r.offset = 0
263 } else {
264 r.offset = int(i.run.NumQueuePairs) * rSize
265 }
266 r.offset += ringIndex * rSize
267
268 return r
269}
270
271// putRing put the ring to the shared memory
272func (q *Queue) putRing() {
273 copy(q.i.regions[q.ring.region].data[q.ring.offset:], q.ring.rb)
274}
275
276// updateRing updates ring with data from shared memory
277func (q *Queue) updateRing() {
278 copy(q.ring.rb, q.i.regions[q.ring.region].data[q.ring.offset:])
279}
280
281func (r *ring) getCookie() int {
282 return (int)(binary.LittleEndian.Uint32((r.rb)[ringCookieOffset:]))
283}
284
285// getFlags returns the flags value from ring buffer
286// Use Queue.getFlags in fast-path to avoid updating the whole ring.
287func (r *ring) getFlags() int {
288 return (int)(binary.LittleEndian.Uint16((r.rb)[ringFlagsOffset:]))
289}
290
291// getHead returns the head pointer value from ring buffer.
292// Use readHead in fast-path to avoid updating the whole ring.
293func (r *ring) getHead() int {
294 return (int)(binary.LittleEndian.Uint16((r.rb)[ringHeadOffset:]))
295}
296
297// getTail returns the tail pointer value from ring buffer.
298// Use readTail in fast-path to avoid updating the whole ring.
299func (r *ring) getTail() int {
300 return (int)(binary.LittleEndian.Uint16((r.rb)[ringTailOffset:]))
301}
302
303func (r *ring) setCookie(val int) {
304 binary.LittleEndian.PutUint32((r.rb)[ringCookieOffset:], uint32(val))
305}
306
307func (r *ring) setFlags(val int) {
308 binary.LittleEndian.PutUint16((r.rb)[ringFlagsOffset:], uint16(val))
309}
310
311// setHead set the head pointer value int the ring buffer.
312// Use writeHead in fast-path to avoid putting the whole ring into shared memory.
313func (r *ring) setHead(val int) {
314 binary.LittleEndian.PutUint16((r.rb)[ringHeadOffset:], uint16(val))
315}
316
317// setTail set the tail pointer value int the ring buffer.
318// Use writeTail in fast-path to avoid putting the whole ring into shared memory.
319func (r *ring) setTail(val int) {
320 binary.LittleEndian.PutUint16((r.rb)[ringTailOffset:], uint16(val))
321}
322
323/* RING END */
324
325// isInterrupt returns true if the queue is in interrupt mode
326func (q *Queue) isInterrupt() bool {
327 return (q.getFlags() & ringFlagInterrupt) == 0
328}
329
330// interrupt performs an interrupt if the queue is in interrupt mode
331func (q *Queue) interrupt() error {
332 if q.isInterrupt() {
333 buf := make([]byte, 8)
334 binary.PutUvarint(buf, 1)
335 n, err := syscall.Write(q.interruptFd, buf[:])
336 if err != nil {
337 return err
338 }
339 if n != 8 {
340 return fmt.Errorf("Faild to write to eventfd")
341 }
342 }
343
344 return nil
345}