github.com/sagernet/gvisor@v0.0.0-20240428053021-e691de28565f/pkg/tcpip/link/sharedmem/queue/tx.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 package queue 16 17 import ( 18 "encoding/binary" 19 20 "github.com/sagernet/gvisor/pkg/atomicbitops" 21 "github.com/sagernet/gvisor/pkg/log" 22 "github.com/sagernet/gvisor/pkg/tcpip/link/sharedmem/pipe" 23 ) 24 25 const ( 26 // Offsets within a packet header. 27 packetID = 0 28 packetSize = 8 29 packetReserved = 12 30 31 sizeOfPacketHeader = 16 32 33 // Offsets with a buffer descriptor 34 bufferOffset = 0 35 bufferSize = 8 36 37 sizeOfBufferDescriptor = 12 38 ) 39 40 // TxBuffer is the descriptor of a transmit buffer. 41 type TxBuffer struct { 42 Next *TxBuffer 43 Offset uint64 44 Size uint32 45 } 46 47 // Tx is a transmit queue. It is implemented with one tx and one rx pipe: the 48 // tx pipe is used to request the transmission of packets, while the rx pipe 49 // is used to receive which transmissions have completed. 50 // 51 // This struct is thread-compatible. 52 type Tx struct { 53 tx pipe.Tx 54 rx pipe.Rx 55 sharedEventFDState *atomicbitops.Uint32 56 } 57 58 // Init initializes the transmit queue with the given pipes. 59 func (t *Tx) Init(tx, rx []byte, sharedEventFDState *atomicbitops.Uint32) { 60 t.tx.Init(tx) 61 t.rx.Init(rx) 62 t.sharedEventFDState = sharedEventFDState 63 } 64 65 // NotificationsEnabled returns true if eventFD should be used to notify the 66 // peer of events (eg. packet transmit etc). 67 func (t *Tx) NotificationsEnabled() bool { 68 // Notifications are considered enabled unless explicitly disabled. 69 return t.sharedEventFDState.Load() != EventFDDisabled 70 } 71 72 // Enqueue queues the given linked list of buffers for transmission as one 73 // packet. While it is queued, the caller must not modify them. 74 func (t *Tx) Enqueue(id uint64, totalDataLen, bufferCount uint32, buffer *TxBuffer) bool { 75 // Reserve room in the tx pipe. 76 totalLen := sizeOfPacketHeader + uint64(bufferCount)*sizeOfBufferDescriptor 77 78 b := t.tx.Push(totalLen) 79 if b == nil { 80 return false 81 } 82 83 // Initialize the packet and buffer descriptors. 84 binary.LittleEndian.PutUint64(b[packetID:], id) 85 binary.LittleEndian.PutUint32(b[packetSize:], totalDataLen) 86 binary.LittleEndian.PutUint32(b[packetReserved:], 0) 87 88 offset := sizeOfPacketHeader 89 for i := bufferCount; i != 0; i-- { 90 binary.LittleEndian.PutUint64(b[offset+bufferOffset:], buffer.Offset) 91 binary.LittleEndian.PutUint32(b[offset+bufferSize:], buffer.Size) 92 offset += sizeOfBufferDescriptor 93 buffer = buffer.Next 94 } 95 96 t.tx.Flush() 97 98 return true 99 } 100 101 // CompletedPacket returns the id of the last completed transmission. The 102 // returned id, if any, refers to a value passed on a previous call to 103 // Enqueue(). 104 func (t *Tx) CompletedPacket() (id uint64, ok bool) { 105 for { 106 b := t.rx.Pull() 107 if b == nil { 108 return 0, false 109 } 110 111 if len(b) != 8 { 112 t.rx.Flush() 113 log.Warningf("Ignoring completed packet: size (%v) is less than expected (%v)", len(b), 8) 114 continue 115 } 116 117 v := binary.LittleEndian.Uint64(b) 118 119 t.rx.Flush() 120 121 return v, true 122 } 123 } 124 125 // Bytes returns the byte slices on which the queue operates. 126 func (t *Tx) Bytes() (tx, rx []byte) { 127 return t.tx.Bytes(), t.rx.Bytes() 128 } 129 130 // TxPacketInfo holds information about a packet sent on a tx queue. 131 type TxPacketInfo struct { 132 ID uint64 133 Size uint32 134 Reserved uint32 135 BufferCount int 136 } 137 138 // DecodeTxPacketHeader decodes the header of a packet sent over a tx queue. 139 func DecodeTxPacketHeader(b []byte) TxPacketInfo { 140 return TxPacketInfo{ 141 ID: binary.LittleEndian.Uint64(b[packetID:]), 142 Size: binary.LittleEndian.Uint32(b[packetSize:]), 143 Reserved: binary.LittleEndian.Uint32(b[packetReserved:]), 144 BufferCount: (len(b) - sizeOfPacketHeader) / sizeOfBufferDescriptor, 145 } 146 } 147 148 // DecodeTxBufferHeader decodes the header of the i-th buffer of a packet sent 149 // over a tx queue. 150 func DecodeTxBufferHeader(b []byte, i int) TxBuffer { 151 b = b[sizeOfPacketHeader+i*sizeOfBufferDescriptor:] 152 return TxBuffer{ 153 Offset: binary.LittleEndian.Uint64(b[bufferOffset:]), 154 Size: binary.LittleEndian.Uint32(b[bufferSize:]), 155 } 156 } 157 158 // EncodeTxCompletion encodes a tx completion header. 159 func EncodeTxCompletion(b []byte, id uint64) { 160 binary.LittleEndian.PutUint64(b, id) 161 }