github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/link/qdisc/fifo/endpoint.go (about) 1 // Copyright 2020 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 fifo provides the implementation of data-link layer endpoints that 16 // wrap another endpoint and queues all outbound packets and asynchronously 17 // dispatches them to the lower endpoint. 18 package fifo 19 20 import ( 21 "github.com/SagerNet/gvisor/pkg/sleep" 22 "github.com/SagerNet/gvisor/pkg/sync" 23 "github.com/SagerNet/gvisor/pkg/tcpip" 24 "github.com/SagerNet/gvisor/pkg/tcpip/header" 25 "github.com/SagerNet/gvisor/pkg/tcpip/stack" 26 ) 27 28 var _ stack.LinkEndpoint = (*endpoint)(nil) 29 var _ stack.GSOEndpoint = (*endpoint)(nil) 30 31 // endpoint represents a LinkEndpoint which implements a FIFO queue for all 32 // outgoing packets. endpoint can have 1 or more underlying queueDispatchers. 33 // All outgoing packets are consistenly hashed to a single underlying queue 34 // using the PacketBuffer.Hash if set, otherwise all packets are queued to the 35 // first queue to avoid reordering in case of missing hash. 36 type endpoint struct { 37 dispatcher stack.NetworkDispatcher 38 lower stack.LinkEndpoint 39 wg sync.WaitGroup 40 dispatchers []*queueDispatcher 41 } 42 43 // queueDispatcher is responsible for dispatching all outbound packets in its 44 // queue. It will also smartly batch packets when possible and write them 45 // through the lower LinkEndpoint. 46 type queueDispatcher struct { 47 lower stack.LinkEndpoint 48 q *packetBufferQueue 49 newPacketWaker sleep.Waker 50 closeWaker sleep.Waker 51 } 52 53 // New creates a new fifo link endpoint with the n queues with maximum 54 // capacity of queueLen. 55 func New(lower stack.LinkEndpoint, n int, queueLen int) stack.LinkEndpoint { 56 e := &endpoint{ 57 lower: lower, 58 } 59 // Create the required dispatchers 60 for i := 0; i < n; i++ { 61 qd := &queueDispatcher{ 62 q: &packetBufferQueue{limit: queueLen}, 63 lower: lower, 64 } 65 e.dispatchers = append(e.dispatchers, qd) 66 e.wg.Add(1) 67 go func() { 68 defer e.wg.Done() 69 qd.dispatchLoop() 70 }() 71 } 72 return e 73 } 74 75 func (q *queueDispatcher) dispatchLoop() { 76 const newPacketWakerID = 1 77 const closeWakerID = 2 78 s := sleep.Sleeper{} 79 s.AddWaker(&q.newPacketWaker, newPacketWakerID) 80 s.AddWaker(&q.closeWaker, closeWakerID) 81 defer s.Done() 82 83 const batchSize = 32 84 var batch stack.PacketBufferList 85 for { 86 id, ok := s.Fetch(true) 87 if ok && id == closeWakerID { 88 return 89 } 90 for pkt := q.q.dequeue(); pkt != nil; pkt = q.q.dequeue() { 91 batch.PushBack(pkt) 92 if batch.Len() < batchSize && !q.q.empty() { 93 continue 94 } 95 // We pass a protocol of zero here because each packet carries its 96 // NetworkProtocol. 97 q.lower.WritePackets(stack.RouteInfo{}, batch, 0 /* protocol */) 98 for pkt := batch.Front(); pkt != nil; pkt = pkt.Next() { 99 batch.Remove(pkt) 100 } 101 batch.Reset() 102 } 103 } 104 } 105 106 // DeliverNetworkPacket implements stack.NetworkDispatcher.DeliverNetworkPacket. 107 func (e *endpoint) DeliverNetworkPacket(remote, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 108 e.dispatcher.DeliverNetworkPacket(remote, local, protocol, pkt) 109 } 110 111 // DeliverOutboundPacket implements stack.NetworkDispatcher.DeliverOutboundPacket. 112 func (e *endpoint) DeliverOutboundPacket(remote, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 113 e.dispatcher.DeliverOutboundPacket(remote, local, protocol, pkt) 114 } 115 116 // Attach implements stack.LinkEndpoint.Attach. 117 func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) { 118 e.dispatcher = dispatcher 119 e.lower.Attach(e) 120 } 121 122 // IsAttached implements stack.LinkEndpoint.IsAttached. 123 func (e *endpoint) IsAttached() bool { 124 return e.dispatcher != nil 125 } 126 127 // MTU implements stack.LinkEndpoint.MTU. 128 func (e *endpoint) MTU() uint32 { 129 return e.lower.MTU() 130 } 131 132 // Capabilities implements stack.LinkEndpoint.Capabilities. 133 func (e *endpoint) Capabilities() stack.LinkEndpointCapabilities { 134 return e.lower.Capabilities() 135 } 136 137 // MaxHeaderLength implements stack.LinkEndpoint.MaxHeaderLength. 138 func (e *endpoint) MaxHeaderLength() uint16 { 139 return e.lower.MaxHeaderLength() 140 } 141 142 // LinkAddress implements stack.LinkEndpoint.LinkAddress. 143 func (e *endpoint) LinkAddress() tcpip.LinkAddress { 144 return e.lower.LinkAddress() 145 } 146 147 // GSOMaxSize implements stack.GSOEndpoint. 148 func (e *endpoint) GSOMaxSize() uint32 { 149 if gso, ok := e.lower.(stack.GSOEndpoint); ok { 150 return gso.GSOMaxSize() 151 } 152 return 0 153 } 154 155 // SupportedGSO implements stack.GSOEndpoint. 156 func (e *endpoint) SupportedGSO() stack.SupportedGSO { 157 if gso, ok := e.lower.(stack.GSOEndpoint); ok { 158 return gso.SupportedGSO() 159 } 160 return stack.GSONotSupported 161 } 162 163 // WritePacket implements stack.LinkEndpoint.WritePacket. 164 // 165 // The packet must have the following fields populated: 166 // - pkt.EgressRoute 167 // - pkt.GSOOptions 168 // - pkt.NetworkProtocolNumber 169 func (e *endpoint) WritePacket(r stack.RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error { 170 d := e.dispatchers[int(pkt.Hash)%len(e.dispatchers)] 171 if !d.q.enqueue(pkt) { 172 return &tcpip.ErrNoBufferSpace{} 173 } 174 d.newPacketWaker.Assert() 175 return nil 176 } 177 178 // WritePackets implements stack.LinkEndpoint.WritePackets. 179 // 180 // Each packet in the packet buffer list must have the following fields 181 // populated: 182 // - pkt.EgressRoute 183 // - pkt.GSOOptions 184 // - pkt.NetworkProtocolNumber 185 func (e *endpoint) WritePackets(r stack.RouteInfo, pkts stack.PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, tcpip.Error) { 186 enqueued := 0 187 for pkt := pkts.Front(); pkt != nil; { 188 d := e.dispatchers[int(pkt.Hash)%len(e.dispatchers)] 189 nxt := pkt.Next() 190 if !d.q.enqueue(pkt) { 191 if enqueued > 0 { 192 d.newPacketWaker.Assert() 193 } 194 return enqueued, &tcpip.ErrNoBufferSpace{} 195 } 196 pkt = nxt 197 enqueued++ 198 d.newPacketWaker.Assert() 199 } 200 return enqueued, nil 201 } 202 203 // Wait implements stack.LinkEndpoint.Wait. 204 func (e *endpoint) Wait() { 205 e.lower.Wait() 206 207 // The linkEP is gone. Teardown the outbound dispatcher goroutines. 208 for i := range e.dispatchers { 209 e.dispatchers[i].closeWaker.Assert() 210 } 211 212 e.wg.Wait() 213 } 214 215 // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType 216 func (e *endpoint) ARPHardwareType() header.ARPHardwareType { 217 return e.lower.ARPHardwareType() 218 } 219 220 // AddHeader implements stack.LinkEndpoint.AddHeader. 221 func (e *endpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 222 e.lower.AddHeader(local, remote, protocol, pkt) 223 }