docs: correct fib tunnel diagram reference
[vpp.git] / extras / gomemif / memif / interface.go
1 /*
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
18 // Package memif provides the implementation of shared memory interface (memif).
19 //
20 // Memif network interfaces communicate using UNIX domain socket. This socket
21 // must be first created using NewSocket(). Then interfaces can be added
22 // to this socket using NewInterface(). To start communication on each socket
23 // socket.StartPolling() must be called. socket.StopPolling() will stop
24 // the communication. When the interface changes link status Connected and
25 // Disconencted callbacks set in Arguments for each interface are called
26 // respectively. Once the interface is connected rx and tx queues can be
27 // aquired using interface.GetRxQueue() and interface.GetTxQueue().
28 // Packets can be transmitted by calling queue.ReadPacket() on rx queues and
29 // queue.WritePacket() on tx queues. If the interface is disconnected
30 // queue.ReadPacket() and queue.WritePacket() MUST not be called.
31 //
32 // Data transmission is backed by shared memory. The driver works in
33 // promiscuous mode only.
34 package memif
35
36 import (
37         "container/list"
38         "fmt"
39         "os"
40         "syscall"
41 )
42
43 const (
44         DefaultSocketFilename   = "/run/vpp/memif.sock"
45         DefaultNumQueuePairs    = 1
46         DefaultLog2RingSize     = 10
47         DefaultPacketBufferSize = 2048
48 )
49
50 const mfd_allow_sealing = 2
51 const sys_memfd_create = 319
52 const f_add_seals = 1033
53 const f_seal_shrink = 0x0002
54
55 const efd_nonblock = 04000
56
57 // ConnectedFunc is a callback called when an interface is connected
58 type ConnectedFunc func(i *Interface) error
59
60 // DisconnectedFunc is a callback called when an interface is disconnected
61 type DisconnectedFunc func(i *Interface) error
62
63 // MemoryConfig represents shared memory configuration
64 type MemoryConfig struct {
65         NumQueuePairs    uint16 // number of queue pairs
66         Log2RingSize     uint8  // ring size as log2
67         PacketBufferSize uint32 // size of single packet buffer
68 }
69
70 // Arguments represent interface configuration
71 type Arguments struct {
72         Id               uint32 // Interface identifier unique across socket. Used to identify peer interface when connecting
73         IsMaster         bool   // Interface role master/slave
74         Name             string
75         Secret           [24]byte // optional parameter, secrets of the interfaces must match if they are to connect
76         MemoryConfig     MemoryConfig
77         ConnectedFunc    ConnectedFunc    // callback called when interface changes status to connected
78         DisconnectedFunc DisconnectedFunc // callback called when interface changes status to disconnected
79         PrivateData      interface{}      // private data used by client program
80 }
81
82 // memoryRegion represents a shared memory mapped file
83 type memoryRegion struct {
84         data               []byte
85         size               uint64
86         fd                 int
87         packetBufferOffset uint32
88 }
89
90 // Queue represents rx or tx queue
91 type Queue struct {
92         ring        *ring
93         i           *Interface
94         lastHead    uint16
95         lastTail    uint16
96         interruptFd int
97 }
98
99 // Interface represents memif network interface
100 type Interface struct {
101         args        Arguments
102         run         MemoryConfig
103         privateData interface{}
104         listRef     *list.Element
105         socket      *Socket
106         cc          *controlChannel
107         remoteName  string
108         peerName    string
109         regions     []memoryRegion
110         txQueues    []Queue
111         rxQueues    []Queue
112 }
113
114 // IsMaster returns true if the interfaces role is master, else returns false
115 func (i *Interface) IsMaster() bool {
116         return i.args.IsMaster
117 }
118
119 // GetRemoteName returns the name of the application on which the peer
120 // interface exists
121 func (i *Interface) GetRemoteName() string {
122         return i.remoteName
123 }
124
125 // GetPeerName returns peer interfaces name
126 func (i *Interface) GetPeerName() string {
127         return i.peerName
128 }
129
130 // GetName returens interfaces name
131 func (i *Interface) GetName() string {
132         return i.args.Name
133 }
134
135 // GetMemoryConfig returns interfaces active memory config.
136 // If interface is not connected the config is invalid.
137 func (i *Interface) GetMemoryConfig() MemoryConfig {
138         return i.run
139 }
140
141 // GetRxQueue returns an rx queue specified by queue index
142 func (i *Interface) GetRxQueue(qid int) (*Queue, error) {
143         if qid >= len(i.rxQueues) {
144                 return nil, fmt.Errorf("Invalid Queue index")
145         }
146         return &i.rxQueues[qid], nil
147 }
148
149 // GetRxQueue returns a tx queue specified by queue index
150 func (i *Interface) GetTxQueue(qid int) (*Queue, error) {
151         if qid >= len(i.txQueues) {
152                 return nil, fmt.Errorf("Invalid Queue index")
153         }
154         return &i.txQueues[qid], nil
155 }
156
157 // GetEventFd returns queues interrupt event fd
158 func (q *Queue) GetEventFd() (int, error) {
159         return q.interruptFd, nil
160 }
161
162 // GetFilename returns sockets filename
163 func (socket *Socket) GetFilename() string {
164         return socket.filename
165 }
166
167 // close closes the queue
168 func (q *Queue) close() {
169         syscall.Close(q.interruptFd)
170 }
171
172 // IsConnecting returns true if the interface is connecting
173 func (i *Interface) IsConnecting() bool {
174         if i.cc != nil {
175                 return true
176         }
177         return false
178 }
179
180 // IsConnected returns true if the interface is connected
181 func (i *Interface) IsConnected() bool {
182         if i.cc != nil && i.cc.isConnected {
183                 return true
184         }
185         return false
186 }
187
188 // Disconnect disconnects the interface
189 func (i *Interface) Disconnect() (err error) {
190         if i.cc != nil {
191                 // close control and disconenct interface
192                 return i.cc.close(true, "Interface disconnected")
193         }
194         return nil
195 }
196
197 // disconnect finalizes interface disconnection
198 func (i *Interface) disconnect() (err error) {
199         if i.cc == nil { // disconnected
200                 return nil
201         }
202
203         err = i.args.DisconnectedFunc(i)
204         if err != nil {
205                 return fmt.Errorf("DisconnectedFunc: ", err)
206         }
207
208         for _, q := range i.txQueues {
209                 q.close()
210         }
211         i.txQueues = []Queue{}
212
213         for _, q := range i.rxQueues {
214                 q.close()
215         }
216         i.rxQueues = []Queue{}
217
218         // unmap regions
219         for _, r := range i.regions {
220                 err = syscall.Munmap(r.data)
221                 if err != nil {
222                         return err
223                 }
224                 err = syscall.Close(r.fd)
225                 if err != nil {
226                         return err
227                 }
228         }
229         i.regions = nil
230         i.cc = nil
231
232         i.peerName = ""
233         i.remoteName = ""
234
235         return nil
236 }
237
238 // Delete deletes the interface
239 func (i *Interface) Delete() (err error) {
240         i.Disconnect()
241
242         // remove referance on socket
243         i.socket.interfaceList.Remove(i.listRef)
244         i = nil
245
246         return nil
247 }
248
249 // GetSocket returns the socket the interface belongs to
250 func (i *Interface) GetSocket() *Socket {
251         return i.socket
252 }
253
254 // GetPrivateDate returns interfaces private data
255 func (i *Interface) GetPrivateData() interface{} {
256         return i.args.PrivateData
257 }
258
259 // GetId returns interfaces id
260 func (i *Interface) GetId() uint32 {
261         return i.args.Id
262 }
263
264 // RoleToString returns 'Master' if isMaster os true, else returns 'Slave'
265 func RoleToString(isMaster bool) string {
266         if isMaster {
267                 return "Master"
268         }
269         return "Slave"
270 }
271
272 // RequestConnection is used by slave interface to connect to a socket and
273 // create a control channel
274 func (i *Interface) RequestConnection() error {
275         if i.IsMaster() {
276                 return fmt.Errorf("Only slave can request connection")
277         }
278         // create socket
279         fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0)
280         if err != nil {
281                 return fmt.Errorf("Failed to create UNIX domain socket: %v", err)
282         }
283         usa := &syscall.SockaddrUnix{Name: i.socket.filename}
284
285         // Connect to listener socket
286         err = syscall.Connect(fd, usa)
287         if err != nil {
288                 return fmt.Errorf("Failed to connect socket %s : %v", i.socket.filename, err)
289         }
290
291         // Create control channel
292         i.cc, err = i.socket.addControlChannel(fd, i)
293         if err != nil {
294                 return fmt.Errorf("Failed to create control channel: %v", err)
295         }
296
297         return nil
298 }
299
300 // NewInterface returns a new memif network interface. When creating an interface
301 // it's id must be unique across socket with the exception of loopback interface
302 // in which case the id is the same but role differs
303 func (socket *Socket) NewInterface(args *Arguments) (*Interface, error) {
304         var err error
305         // make sure the ID is unique on this socket
306         for elt := socket.interfaceList.Front(); elt != nil; elt = elt.Next() {
307                 i, ok := elt.Value.(*Interface)
308                 if ok {
309                         if i.args.Id == args.Id && i.args.IsMaster == args.IsMaster {
310                                 return nil, fmt.Errorf("Interface with id %u role %s already exists on this socket", args.Id, RoleToString(args.IsMaster))
311                         }
312                 }
313         }
314
315         // copy interface configuration
316         i := Interface{
317                 args: *args,
318         }
319         // set default values
320         if i.args.MemoryConfig.NumQueuePairs == 0 {
321                 i.args.MemoryConfig.NumQueuePairs = DefaultNumQueuePairs
322         }
323         if i.args.MemoryConfig.Log2RingSize == 0 {
324                 i.args.MemoryConfig.Log2RingSize = DefaultLog2RingSize
325         }
326         if i.args.MemoryConfig.PacketBufferSize == 0 {
327                 i.args.MemoryConfig.PacketBufferSize = DefaultPacketBufferSize
328         }
329
330         i.socket = socket
331
332         // append interface to the list
333         i.listRef = socket.interfaceList.PushBack(&i)
334
335         if i.args.IsMaster {
336                 if socket.listener == nil {
337                         err = socket.addListener()
338                         if err != nil {
339                                 return nil, fmt.Errorf("Failed to create listener channel: %s", err)
340                         }
341                 }
342         }
343
344         return &i, nil
345 }
346
347 // eventFd returns an eventfd (SYS_EVENTFD2)
348 func eventFd() (efd int, err error) {
349         u_efd, _, errno := syscall.Syscall(syscall.SYS_EVENTFD2, uintptr(0), uintptr(efd_nonblock), 0)
350         if errno != 0 {
351                 return -1, os.NewSyscallError("eventfd", errno)
352         }
353         return int(u_efd), nil
354 }
355
356 // addRegions creates and adds a new memory region to the interface (slave only)
357 func (i *Interface) addRegion(hasPacketBuffers bool, hasRings bool) (err error) {
358         var r memoryRegion
359
360         if hasRings {
361                 r.packetBufferOffset = uint32((i.run.NumQueuePairs + i.run.NumQueuePairs) * (ringSize + descSize*(1<<i.run.Log2RingSize)))
362         } else {
363                 r.packetBufferOffset = 0
364         }
365
366         if hasPacketBuffers {
367                 r.size = uint64(r.packetBufferOffset + i.run.PacketBufferSize*uint32(1<<i.run.Log2RingSize)*uint32(i.run.NumQueuePairs+i.run.NumQueuePairs))
368         } else {
369                 r.size = uint64(r.packetBufferOffset)
370         }
371
372         r.fd, err = memfdCreate()
373         if err != nil {
374                 return err
375         }
376
377         _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(r.fd), uintptr(f_add_seals), uintptr(f_seal_shrink))
378         if errno != 0 {
379                 syscall.Close(r.fd)
380                 return fmt.Errorf("memfdCreate: %s", os.NewSyscallError("fcntl", errno))
381         }
382
383         err = syscall.Ftruncate(r.fd, int64(r.size))
384         if err != nil {
385                 syscall.Close(r.fd)
386                 r.fd = -1
387                 return fmt.Errorf("memfdCreate: %s", err)
388         }
389
390         r.data, err = syscall.Mmap(r.fd, 0, int(r.size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
391         if err != nil {
392                 return fmt.Errorf("addRegion: %s", err)
393         }
394
395         i.regions = append(i.regions, r)
396
397         return nil
398 }
399
400 // initializeRegions initializes interfaces regions (slave only)
401 func (i *Interface) initializeRegions() (err error) {
402
403         err = i.addRegion(true, true)
404         if err != nil {
405                 return fmt.Errorf("initializeRegions: %s", err)
406         }
407
408         return nil
409 }
410
411 // initializeQueues initializes interfaces queues (slave only)
412 func (i *Interface) initializeQueues() (err error) {
413         var q *Queue
414         var desc descBuf
415         var slot int
416
417         desc = newDescBuf()
418         desc.setFlags(0)
419         desc.setRegion(0)
420         desc.setLength(int(i.run.PacketBufferSize))
421
422         for qid := 0; qid < int(i.run.NumQueuePairs); qid++ {
423                 /* TX */
424                 q = &Queue{
425                         ring:     i.newRing(0, ringTypeS2M, qid),
426                         lastHead: 0,
427                         lastTail: 0,
428                         i:        i,
429                 }
430                 q.ring.setCookie(cookie)
431                 q.ring.setFlags(1)
432                 q.interruptFd, err = eventFd()
433                 if err != nil {
434                         return err
435                 }
436                 q.putRing()
437                 i.txQueues = append(i.txQueues, *q)
438
439                 for j := 0; j < q.ring.size; j++ {
440                         slot = qid*q.ring.size + j
441                         desc.setOffset(int(i.regions[0].packetBufferOffset + uint32(slot)*i.run.PacketBufferSize))
442                         q.putDescBuf(slot, desc)
443                 }
444         }
445         for qid := 0; qid < int(i.run.NumQueuePairs); qid++ {
446                 /* RX */
447                 q = &Queue{
448                         ring:     i.newRing(0, ringTypeM2S, qid),
449                         lastHead: 0,
450                         lastTail: 0,
451                         i:        i,
452                 }
453                 q.ring.setCookie(cookie)
454                 q.ring.setFlags(1)
455                 q.interruptFd, err = eventFd()
456                 if err != nil {
457                         return err
458                 }
459                 q.putRing()
460                 i.rxQueues = append(i.rxQueues, *q)
461
462                 for j := 0; j < q.ring.size; j++ {
463                         slot = qid*q.ring.size + j
464                         desc.setOffset(int(i.regions[0].packetBufferOffset + uint32(slot)*i.run.PacketBufferSize))
465                         q.putDescBuf(slot, desc)
466                 }
467         }
468
469         return nil
470 }
471
472 // connect finalizes interface connection
473 func (i *Interface) connect() (err error) {
474         for rid, _ := range i.regions {
475                 r := &i.regions[rid]
476                 if r.data == nil {
477                         r.data, err = syscall.Mmap(r.fd, 0, int(r.size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
478                         if err != nil {
479                                 return fmt.Errorf("Mmap: %s", err)
480                         }
481                 }
482         }
483
484         for _, q := range i.txQueues {
485                 q.updateRing()
486
487                 if q.ring.getCookie() != cookie {
488                         return fmt.Errorf("Wrong cookie")
489                 }
490
491                 q.lastHead = 0
492                 q.lastTail = 0
493         }
494
495         for _, q := range i.rxQueues {
496                 q.updateRing()
497
498                 if q.ring.getCookie() != cookie {
499                         return fmt.Errorf("Wrong cookie")
500                 }
501
502                 q.lastHead = 0
503                 q.lastTail = 0
504         }
505
506         return i.args.ConnectedFunc(i)
507 }