github.com/FlowerWrong/netstack@v0.0.0-20191009141956-e5848263af28/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/FlowerWrong/netstack/tcpip/link/sharedmem/pipe"
    21  	"log"
    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.Printf("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  }