github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/tcpip/link/sharedmem/server_rx.go (about) 1 // Copyright 2021 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 //go:build linux 16 // +build linux 17 18 package sharedmem 19 20 import ( 21 "golang.org/x/sys/unix" 22 "github.com/nicocha30/gvisor-ligolo/pkg/atomicbitops" 23 "github.com/nicocha30/gvisor-ligolo/pkg/buffer" 24 "github.com/nicocha30/gvisor-ligolo/pkg/cleanup" 25 "github.com/nicocha30/gvisor-ligolo/pkg/eventfd" 26 "github.com/nicocha30/gvisor-ligolo/pkg/tcpip/link/sharedmem/pipe" 27 "github.com/nicocha30/gvisor-ligolo/pkg/tcpip/link/sharedmem/queue" 28 ) 29 30 type serverRx struct { 31 // packetPipe represents the receive end of the pipe that carries the packet 32 // descriptors sent by the client. 33 packetPipe pipe.Rx 34 35 // completionPipe represents the transmit end of the pipe that will carry 36 // completion notifications from the server to the client. 37 completionPipe pipe.Tx 38 39 // data represents the buffer area where the packet payload is held. 40 data []byte 41 42 // eventFD is used to notify the peer when transmission is completed. 43 eventFD eventfd.Eventfd 44 45 // sharedData the memory region to use to enable/disable notifications. 46 sharedData []byte 47 48 // sharedEventFDState is the memory region in sharedData used to enable 49 // disable notifications on eventFD. 50 sharedEventFDState *atomicbitops.Uint32 51 } 52 53 // init initializes all state needed by the serverTx queue based on the 54 // information provided. 55 // 56 // The caller always retains ownership of all file descriptors passed in. The 57 // queue implementation will duplicate any that it may need in the future. 58 func (s *serverRx) init(c *QueueConfig) error { 59 // Map in all buffers. 60 packetPipeMem, err := getBuffer(c.TxPipeFD) 61 if err != nil { 62 return err 63 } 64 cu := cleanup.Make(func() { unix.Munmap(packetPipeMem) }) 65 defer cu.Clean() 66 67 completionPipeMem, err := getBuffer(c.RxPipeFD) 68 if err != nil { 69 return err 70 } 71 cu.Add(func() { unix.Munmap(completionPipeMem) }) 72 73 data, err := getBuffer(c.DataFD) 74 if err != nil { 75 return err 76 } 77 cu.Add(func() { unix.Munmap(data) }) 78 79 sharedData, err := getBuffer(c.SharedDataFD) 80 if err != nil { 81 return err 82 } 83 cu.Add(func() { unix.Munmap(sharedData) }) 84 85 // Duplicate the eventFD so that caller can close it but we can still 86 // use it. 87 efd, err := c.EventFD.Dup() 88 if err != nil { 89 return err 90 } 91 cu.Add(func() { efd.Close() }) 92 93 s.packetPipe.Init(packetPipeMem) 94 s.completionPipe.Init(completionPipeMem) 95 s.data = data 96 s.eventFD = efd 97 s.sharedData = sharedData 98 s.sharedEventFDState = sharedDataPointer(sharedData) 99 100 cu.Release() 101 return nil 102 } 103 104 func (s *serverRx) cleanup() { 105 unix.Munmap(s.packetPipe.Bytes()) 106 unix.Munmap(s.completionPipe.Bytes()) 107 unix.Munmap(s.data) 108 unix.Munmap(s.sharedData) 109 s.eventFD.Close() 110 } 111 112 // EnableNotification updates the shared state such that the peer will notify 113 // the eventfd when there are packets to be dequeued. 114 func (s *serverRx) EnableNotification() { 115 s.sharedEventFDState.Store(queue.EventFDEnabled) 116 } 117 118 // DisableNotification updates the shared state such that the peer will not 119 // notify the eventfd. 120 func (s *serverRx) DisableNotification() { 121 s.sharedEventFDState.Store(queue.EventFDDisabled) 122 } 123 124 // completionNotificationSize is size in bytes of a completion notification sent 125 // on the completion queue after a transmitted packet has been handled. 126 const completionNotificationSize = 8 127 128 // receive receives a single packet from the packetPipe. 129 func (s *serverRx) receive() *buffer.View { 130 desc := s.packetPipe.Pull() 131 if desc == nil { 132 return nil 133 } 134 135 pktInfo := queue.DecodeTxPacketHeader(desc) 136 contents := buffer.NewView(int(pktInfo.Size)) 137 toCopy := pktInfo.Size 138 for i := 0; i < pktInfo.BufferCount; i++ { 139 txBuf := queue.DecodeTxBufferHeader(desc, i) 140 if txBuf.Size <= toCopy { 141 contents.Write(s.data[txBuf.Offset:][:txBuf.Size]) 142 toCopy -= txBuf.Size 143 continue 144 } 145 contents.Write(s.data[txBuf.Offset:][:toCopy]) 146 break 147 } 148 149 // Flush to let peer know that slots queued for transmission have been handled 150 // and its free to reuse the slots. 151 s.packetPipe.Flush() 152 // Encode packet completion. 153 b := s.completionPipe.Push(completionNotificationSize) 154 queue.EncodeTxCompletion(b, pktInfo.ID) 155 s.completionPipe.Flush() 156 return contents 157 } 158 159 func (s *serverRx) waitForPackets() { 160 s.eventFD.Wait() 161 }