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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
18 // Package memif provides the implementation of shared memory interface (memif).
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.
32 // Data transmission is backed by shared memory. The driver works in
33 // promiscuous mode only.
44 DefaultSocketFilename = "/run/vpp/memif.sock"
45 DefaultNumQueuePairs = 1
46 DefaultLog2RingSize = 10
47 DefaultPacketBufferSize = 2048
50 const mfd_allow_sealing = 2
51 const sys_memfd_create = 319
52 const f_add_seals = 1033
53 const f_seal_shrink = 0x0002
55 const efd_nonblock = 04000
57 // ConnectedFunc is a callback called when an interface is connected
58 type ConnectedFunc func(i *Interface) error
60 // DisconnectedFunc is a callback called when an interface is disconnected
61 type DisconnectedFunc func(i *Interface) error
63 type InterruptFunc func(i *Interface) error
65 // MemoryConfig represents shared memory configuration
66 type MemoryConfig struct {
67 NumQueuePairs uint16 // number of queue pairs
68 Log2RingSize uint8 // ring size as log2
69 PacketBufferSize uint32 // size of single packet buffer
72 // Arguments represent interface configuration
73 type Arguments struct {
74 Id uint32 // Interface identifier unique across socket. Used to identify peer interface when connecting
75 IsMaster bool // Interface role master/slave
78 Secret [24]byte // optional parameter, secrets of the interfaces must match if they are to connect
79 MemoryConfig MemoryConfig
80 ConnectedFunc ConnectedFunc // callback called when interface changes status to connected
81 DisconnectedFunc DisconnectedFunc // callback called when interface changes status to disconnected
82 InterruptFunc InterruptFunc
83 PrivateData interface{} // private data used by client program
87 // memoryRegion represents a shared memory mapped file
88 type memoryRegion struct {
92 packetBufferOffset uint32
95 // Queue represents rx or tx queue
104 // Interface represents memif network interface
105 type Interface struct {
108 privateData interface{}
109 listRef *list.Element
114 regions []memoryRegion
117 onInterrupt InterruptFunc
120 // IsMaster returns true if the interfaces role is master, else returns false
121 func (i *Interface) IsMaster() bool {
122 return i.args.IsMaster
125 // GetRemoteName returns the name of the application on which the peer
127 func (i *Interface) GetRemoteName() string {
131 // GetPeerName returns peer interfaces name
132 func (i *Interface) GetPeerName() string {
136 // GetName returens interfaces name
137 func (i *Interface) GetName() string {
141 // GetMemoryConfig returns interfaces active memory config.
142 // If interface is not connected the config is invalid.
143 func (i *Interface) GetMemoryConfig() MemoryConfig {
147 // GetRxQueue returns an rx queue specified by queue index
148 func (i *Interface) GetRxQueue(qid int) (*Queue, error) {
149 if qid >= len(i.rxQueues) {
150 return nil, fmt.Errorf("Invalid Queue index")
152 return &i.rxQueues[qid], nil
155 // GetRxQueue returns a tx queue specified by queue index
156 func (i *Interface) GetTxQueue(qid int) (*Queue, error) {
157 if qid >= len(i.txQueues) {
158 return nil, fmt.Errorf("Invalid Queue index")
160 return &i.txQueues[qid], nil
163 // GetEventFd returns queues interrupt event fd
164 func (q *Queue) GetEventFd() (int, error) {
165 return q.interruptFd, nil
168 // GetFilename returns sockets filename
169 func (socket *Socket) GetFilename() string {
170 return socket.filename
173 // close closes the queue
174 func (q *Queue) close() {
175 syscall.Close(q.interruptFd)
178 // IsConnecting returns true if the interface is connecting
179 func (i *Interface) IsConnecting() bool {
186 // IsConnected returns true if the interface is connected
187 func (i *Interface) IsConnected() bool {
188 if i.cc != nil && i.cc.isConnected {
194 // Disconnect disconnects the interface
195 func (i *Interface) Disconnect() (err error) {
197 // close control and disconenct interface
198 return i.cc.close(true, "Interface disconnected")
203 // disconnect finalizes interface disconnection
204 func (i *Interface) disconnect() (err error) {
205 if i.cc == nil { // disconnected
209 err = i.args.DisconnectedFunc(i)
211 return fmt.Errorf("DisconnectedFunc: ", err)
214 for _, q := range i.txQueues {
217 i.txQueues = []Queue{}
219 for _, q := range i.rxQueues {
222 i.rxQueues = []Queue{}
225 for _, r := range i.regions {
226 err = syscall.Munmap(r.data)
230 err = syscall.Close(r.fd)
244 // Delete deletes the interface
245 func (i *Interface) Delete() (err error) {
248 // remove referance on socket
249 i.socket.interfaceList.Remove(i.listRef)
255 // GetSocket returns the socket the interface belongs to
256 func (i *Interface) GetSocket() *Socket {
260 // GetPrivateDate returns interfaces private data
261 func (i *Interface) GetPrivateData() interface{} {
262 return i.args.PrivateData
265 // GetId returns interfaces id
266 func (i *Interface) GetId() uint32 {
270 // RoleToString returns 'Master' if isMaster os true, else returns 'Slave'
271 func RoleToString(isMaster bool) string {
278 func memifPathIsAbstract(filename string) bool {
279 return (filename[0] == '@')
282 // RequestConnection is used by slave interface to connect to a socket and
283 // create a control channel
284 func (i *Interface) RequestConnection() error {
286 return fmt.Errorf("Only slave can request connection")
289 fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0)
291 return fmt.Errorf("Failed to create UNIX domain socket: %v", err)
293 usa := &syscall.SockaddrUnix{Name: i.socket.filename}
295 if memifPathIsAbstract(i.socket.GetFilename()) {
296 usa.Name = "\000" + usa.Name[1:]
298 // Connect to listener socket
299 err = syscall.Connect(fd, usa)
301 return fmt.Errorf("Failed to connect socket %s : %v", i.socket.filename, err)
304 // Create control channel
305 i.cc, err = i.socket.addControlChannel(fd, i)
307 return fmt.Errorf("Failed to create control channel: %v", err)
313 // NewInterface returns a new memif network interface. When creating an interface
314 // it's id must be unique across socket with the exception of loopback interface
315 // in which case the id is the same but role differs
316 func (socket *Socket) NewInterface(args *Arguments) (*Interface, error) {
318 // make sure the ID is unique on this socket
319 for elt := socket.interfaceList.Front(); elt != nil; elt = elt.Next() {
320 i, ok := elt.Value.(*Interface)
322 if i.args.Id == args.Id && i.args.IsMaster == args.IsMaster {
323 return nil, fmt.Errorf("Interface with id %u role %s already exists on this socket", args.Id, RoleToString(args.IsMaster))
328 // copy interface configuration
331 onInterrupt: args.InterruptFunc,
333 // set default values
334 if i.args.MemoryConfig.NumQueuePairs == 0 {
335 i.args.MemoryConfig.NumQueuePairs = DefaultNumQueuePairs
337 if i.args.MemoryConfig.Log2RingSize == 0 {
338 i.args.MemoryConfig.Log2RingSize = DefaultLog2RingSize
340 if i.args.MemoryConfig.PacketBufferSize == 0 {
341 i.args.MemoryConfig.PacketBufferSize = DefaultPacketBufferSize
346 // append interface to the list
347 i.listRef = socket.interfaceList.PushBack(&i)
350 if socket.listener == nil {
351 err = socket.addListener()
353 return nil, fmt.Errorf("Failed to create listener channel: %s", err)
361 // eventFd returns an eventfd (SYS_EVENTFD2)
362 func eventFd() (efd int, err error) {
363 u_efd, _, errno := syscall.Syscall(syscall.SYS_EVENTFD2, uintptr(0), uintptr(efd_nonblock), 0)
365 return -1, os.NewSyscallError("eventfd", errno)
367 return int(u_efd), nil
370 // addRegions creates and adds a new memory region to the interface (slave only)
371 func (i *Interface) addRegion(hasPacketBuffers bool, hasRings bool) (err error) {
375 r.packetBufferOffset = uint32((i.run.NumQueuePairs + i.run.NumQueuePairs) * (ringSize + descSize*(1<<i.run.Log2RingSize)))
377 r.packetBufferOffset = 0
380 if hasPacketBuffers {
381 r.size = uint64(r.packetBufferOffset + i.run.PacketBufferSize*uint32(1<<i.run.Log2RingSize)*uint32(i.run.NumQueuePairs+i.run.NumQueuePairs))
383 r.size = uint64(r.packetBufferOffset)
386 r.fd, err = memfdCreate()
391 _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(r.fd), uintptr(f_add_seals), uintptr(f_seal_shrink))
394 return fmt.Errorf("memfdCreate: %s", os.NewSyscallError("fcntl", errno))
397 err = syscall.Ftruncate(r.fd, int64(r.size))
401 return fmt.Errorf("memfdCreate: %s", err)
404 r.data, err = syscall.Mmap(r.fd, 0, int(r.size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
406 return fmt.Errorf("addRegion: %s", err)
409 i.regions = append(i.regions, r)
414 // initializeRegions initializes interfaces regions (slave only)
415 func (i *Interface) initializeRegions() (err error) {
417 err = i.addRegion(true, true)
419 return fmt.Errorf("initializeRegions: %s", err)
425 // initializeQueues initializes interfaces queues (slave only)
426 func (i *Interface) initializeQueues() (err error) {
434 desc.setLength(int(i.run.PacketBufferSize))
436 for qid := 0; qid < int(i.run.NumQueuePairs); qid++ {
439 ring: i.newRing(0, ringTypeS2M, qid),
444 q.ring.setCookie(cookie)
446 q.interruptFd, err = eventFd()
450 i.socket.addInterrupt(q.interruptFd)
452 i.txQueues = append(i.txQueues, *q)
454 for j := 0; j < q.ring.size; j++ {
455 slot = qid*q.ring.size + j
456 desc.setOffset(int(i.regions[0].packetBufferOffset + uint32(slot)*i.run.PacketBufferSize))
457 q.putDescBuf(slot, desc)
460 for qid := 0; qid < int(i.run.NumQueuePairs); qid++ {
463 ring: i.newRing(0, ringTypeM2S, qid),
468 q.ring.setCookie(cookie)
469 if i.args.InterruptFunc == nil {
474 q.interruptFd, err = eventFd()
478 i.args.InterruptFd = uint16(q.interruptFd)
479 i.socket.addInterrupt(q.interruptFd)
481 i.rxQueues = append(i.rxQueues, *q)
483 for j := 0; j < q.ring.size; j++ {
484 slot = qid*q.ring.size + j
485 desc.setOffset(int(i.regions[0].packetBufferOffset + uint32(slot)*i.run.PacketBufferSize))
486 q.putDescBuf(slot, desc)
493 // connect finalizes interface connection
494 func (i *Interface) connect() (err error) {
495 for rid, _ := range i.regions {
498 r.data, err = syscall.Mmap(r.fd, 0, int(r.size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
500 return fmt.Errorf("Mmap: %s", err)
505 for _, q := range i.txQueues {
508 if q.ring.getCookie() != cookie {
509 return fmt.Errorf("Wrong cookie")
516 for _, q := range i.rxQueues {
519 if q.ring.getCookie() != cookie {
520 return fmt.Errorf("Wrong cookie")
527 return i.args.ConnectedFunc(i)