github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/link/sharedmem/rx.go (about) 1 // Copyright 2018 The gVisor Authors. 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 // +build linux 16 17 package sharedmem 18 19 import ( 20 "sync/atomic" 21 22 "golang.org/x/sys/unix" 23 "github.com/SagerNet/gvisor/pkg/tcpip/link/rawfile" 24 "github.com/SagerNet/gvisor/pkg/tcpip/link/sharedmem/queue" 25 ) 26 27 // rx holds all state associated with an rx queue. 28 type rx struct { 29 data []byte 30 sharedData []byte 31 q queue.Rx 32 eventFD int 33 } 34 35 // init initializes all state needed by the rx queue based on the information 36 // provided. 37 // 38 // The caller always retains ownership of all file descriptors passed in. The 39 // queue implementation will duplicate any that it may need in the future. 40 func (r *rx) init(mtu uint32, c *QueueConfig) error { 41 // Map in all buffers. 42 txPipe, err := getBuffer(c.TxPipeFD) 43 if err != nil { 44 return err 45 } 46 47 rxPipe, err := getBuffer(c.RxPipeFD) 48 if err != nil { 49 unix.Munmap(txPipe) 50 return err 51 } 52 53 data, err := getBuffer(c.DataFD) 54 if err != nil { 55 unix.Munmap(txPipe) 56 unix.Munmap(rxPipe) 57 return err 58 } 59 60 sharedData, err := getBuffer(c.SharedDataFD) 61 if err != nil { 62 unix.Munmap(txPipe) 63 unix.Munmap(rxPipe) 64 unix.Munmap(data) 65 return err 66 } 67 68 // Duplicate the eventFD so that caller can close it but we can still 69 // use it. 70 efd, err := unix.Dup(c.EventFD) 71 if err != nil { 72 unix.Munmap(txPipe) 73 unix.Munmap(rxPipe) 74 unix.Munmap(data) 75 unix.Munmap(sharedData) 76 return err 77 } 78 79 // Set the eventfd as non-blocking. 80 if err := unix.SetNonblock(efd, true); err != nil { 81 unix.Munmap(txPipe) 82 unix.Munmap(rxPipe) 83 unix.Munmap(data) 84 unix.Munmap(sharedData) 85 unix.Close(efd) 86 return err 87 } 88 89 // Initialize state based on buffers. 90 r.q.Init(txPipe, rxPipe, sharedDataPointer(sharedData)) 91 r.data = data 92 r.eventFD = efd 93 r.sharedData = sharedData 94 95 return nil 96 } 97 98 // cleanup releases all resources allocated during init(). It must only be 99 // called if init() has previously succeeded. 100 func (r *rx) cleanup() { 101 a, b := r.q.Bytes() 102 unix.Munmap(a) 103 unix.Munmap(b) 104 105 unix.Munmap(r.data) 106 unix.Munmap(r.sharedData) 107 unix.Close(r.eventFD) 108 } 109 110 // postAndReceive posts the provided buffers (if any), and then tries to read 111 // from the receive queue. 112 // 113 // Capacity permitting, it reuses the posted buffer slice to store the buffers 114 // that were read as well. 115 // 116 // This function will block if there aren't any available packets. 117 func (r *rx) postAndReceive(b []queue.RxBuffer, stopRequested *uint32) ([]queue.RxBuffer, uint32) { 118 // Post the buffers first. If we cannot post, sleep until we can. We 119 // never post more than will fit concurrently, so it's safe to wait 120 // until enough room is available. 121 if len(b) != 0 && !r.q.PostBuffers(b) { 122 r.q.EnableNotification() 123 for !r.q.PostBuffers(b) { 124 var tmp [8]byte 125 rawfile.BlockingRead(r.eventFD, tmp[:]) 126 if atomic.LoadUint32(stopRequested) != 0 { 127 r.q.DisableNotification() 128 return nil, 0 129 } 130 } 131 r.q.DisableNotification() 132 } 133 134 // Read the next set of descriptors. 135 b, n := r.q.Dequeue(b[:0]) 136 if len(b) != 0 { 137 return b, n 138 } 139 140 // Data isn't immediately available. Enable eventfd notifications. 141 r.q.EnableNotification() 142 for { 143 b, n = r.q.Dequeue(b) 144 if len(b) != 0 { 145 break 146 } 147 148 // Wait for notification. 149 var tmp [8]byte 150 rawfile.BlockingRead(r.eventFD, tmp[:]) 151 if atomic.LoadUint32(stopRequested) != 0 { 152 r.q.DisableNotification() 153 return nil, 0 154 } 155 } 156 r.q.DisableNotification() 157 158 return b, n 159 }