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