inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/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 "inet.af/netstack/sleep" 22 "inet.af/netstack/sync" 23 "inet.af/netstack/tcpip" 24 "inet.af/netstack/tcpip/header" 25 "inet.af/netstack/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 s := sleep.Sleeper{} 77 s.AddWaker(&q.newPacketWaker) 78 s.AddWaker(&q.closeWaker) 79 defer s.Done() 80 81 const batchSize = 32 82 var batch stack.PacketBufferList 83 for { 84 w := s.Fetch(true) 85 if w == &q.closeWaker { 86 return 87 } 88 // Must otherwise be the newPacketWaker. 89 for pkt := q.q.dequeue(); pkt != nil; pkt = q.q.dequeue() { 90 batch.PushBack(pkt) 91 if batch.Len() < batchSize && !q.q.empty() { 92 continue 93 } 94 // We pass a protocol of zero here because each packet carries its 95 // NetworkProtocol. 96 q.lower.WritePackets(stack.RouteInfo{}, batch, 0 /* protocol */) 97 batch.DecRef() 98 batch.Reset() 99 } 100 } 101 } 102 103 // DeliverNetworkPacket implements stack.NetworkDispatcher.DeliverNetworkPacket. 104 func (e *endpoint) DeliverNetworkPacket(remote, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 105 e.dispatcher.DeliverNetworkPacket(remote, local, protocol, pkt) 106 } 107 108 // Attach implements stack.LinkEndpoint.Attach. 109 func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) { 110 // nil means the NIC is being removed. 111 if dispatcher == nil { 112 e.lower.Attach(nil) 113 e.Wait() 114 e.dispatcher = nil 115 return 116 } 117 e.dispatcher = dispatcher 118 e.lower.Attach(e) 119 } 120 121 // IsAttached implements stack.LinkEndpoint.IsAttached. 122 func (e *endpoint) IsAttached() bool { 123 return e.dispatcher != nil 124 } 125 126 // MTU implements stack.LinkEndpoint.MTU. 127 func (e *endpoint) MTU() uint32 { 128 return e.lower.MTU() 129 } 130 131 // Capabilities implements stack.LinkEndpoint.Capabilities. 132 func (e *endpoint) Capabilities() stack.LinkEndpointCapabilities { 133 return e.lower.Capabilities() 134 } 135 136 // MaxHeaderLength implements stack.LinkEndpoint.MaxHeaderLength. 137 func (e *endpoint) MaxHeaderLength() uint16 { 138 return e.lower.MaxHeaderLength() 139 } 140 141 // LinkAddress implements stack.LinkEndpoint.LinkAddress. 142 func (e *endpoint) LinkAddress() tcpip.LinkAddress { 143 return e.lower.LinkAddress() 144 } 145 146 // GSOMaxSize implements stack.GSOEndpoint. 147 func (e *endpoint) GSOMaxSize() uint32 { 148 if gso, ok := e.lower.(stack.GSOEndpoint); ok { 149 return gso.GSOMaxSize() 150 } 151 return 0 152 } 153 154 // SupportedGSO implements stack.GSOEndpoint. 155 func (e *endpoint) SupportedGSO() stack.SupportedGSO { 156 if gso, ok := e.lower.(stack.GSOEndpoint); ok { 157 return gso.SupportedGSO() 158 } 159 return stack.GSONotSupported 160 } 161 162 // WritePacket implements stack.LinkEndpoint.WritePacket. 163 // 164 // The packet must have the following fields populated: 165 // - pkt.EgressRoute 166 // - pkt.GSOOptions 167 // - pkt.NetworkProtocolNumber 168 func (e *endpoint) WritePacket(r stack.RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error { 169 d := e.dispatchers[int(pkt.Hash)%len(e.dispatchers)] 170 if !d.q.enqueue(pkt) { 171 return &tcpip.ErrNoBufferSpace{} 172 } 173 d.newPacketWaker.Assert() 174 return nil 175 } 176 177 // WritePackets implements stack.LinkEndpoint.WritePackets. 178 // 179 // Each packet in the packet buffer list must have the following fields 180 // populated: 181 // - pkt.EgressRoute 182 // - pkt.GSOOptions 183 // - pkt.NetworkProtocolNumber 184 func (e *endpoint) WritePackets(r stack.RouteInfo, pkts stack.PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, tcpip.Error) { 185 enqueued := 0 186 for pkt := pkts.Front(); pkt != nil; { 187 d := e.dispatchers[int(pkt.Hash)%len(e.dispatchers)] 188 nxt := pkt.Next() 189 if !d.q.enqueue(pkt) { 190 if enqueued > 0 { 191 d.newPacketWaker.Assert() 192 } 193 return enqueued, &tcpip.ErrNoBufferSpace{} 194 } 195 pkt = nxt 196 enqueued++ 197 d.newPacketWaker.Assert() 198 } 199 return enqueued, nil 200 } 201 202 // Wait implements stack.LinkEndpoint.Wait. 203 func (e *endpoint) Wait() { 204 e.lower.Wait() 205 206 // The linkEP is gone. Teardown the outbound dispatcher goroutines. 207 for i := range e.dispatchers { 208 e.dispatchers[i].closeWaker.Assert() 209 } 210 211 e.wg.Wait() 212 } 213 214 // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType 215 func (e *endpoint) ARPHardwareType() header.ARPHardwareType { 216 return e.lower.ARPHardwareType() 217 } 218 219 // AddHeader implements stack.LinkEndpoint.AddHeader. 220 func (e *endpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 221 e.lower.AddHeader(local, remote, protocol, pkt) 222 } 223 224 // WriteRawPacket implements stack.LinkEndpoint. 225 func (e *endpoint) WriteRawPacket(pkt *stack.PacketBuffer) tcpip.Error { 226 return e.lower.WriteRawPacket(pkt) 227 }