github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/link/waitable/waitable.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 waitable provides the implementation of data-link layer endpoints 16 // that wrap other endpoints, and can wait for inflight calls to WritePacket or 17 // DeliverNetworkPacket to finish (and new ones to be prevented). 18 // 19 // Waitable endpoints can be used in the networking stack by calling New(eID) to 20 // create a new endpoint, where eID is the ID of the endpoint being wrapped, 21 // and then passing it as an argument to Stack.CreateNIC(). 22 package waitable 23 24 import ( 25 "github.com/SagerNet/gvisor/pkg/sync" 26 "github.com/SagerNet/gvisor/pkg/tcpip" 27 "github.com/SagerNet/gvisor/pkg/tcpip/header" 28 "github.com/SagerNet/gvisor/pkg/tcpip/stack" 29 ) 30 31 // Endpoint is a waitable link-layer endpoint. 32 type Endpoint struct { 33 dispatchGate sync.Gate 34 dispatcher stack.NetworkDispatcher 35 36 writeGate sync.Gate 37 lower stack.LinkEndpoint 38 } 39 40 // New creates a new waitable link-layer endpoint. It wraps around another 41 // endpoint and allows the caller to block new write/dispatch calls and wait for 42 // the inflight ones to finish before returning. 43 func New(lower stack.LinkEndpoint) *Endpoint { 44 return &Endpoint{ 45 lower: lower, 46 } 47 } 48 49 // DeliverNetworkPacket implements stack.NetworkDispatcher.DeliverNetworkPacket. 50 // It is called by the link-layer endpoint being wrapped when a packet arrives, 51 // and only forwards to the actual dispatcher if Wait or WaitDispatch haven't 52 // been called. 53 func (e *Endpoint) DeliverNetworkPacket(remote, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 54 if !e.dispatchGate.Enter() { 55 return 56 } 57 58 e.dispatcher.DeliverNetworkPacket(remote, local, protocol, pkt) 59 e.dispatchGate.Leave() 60 } 61 62 // DeliverOutboundPacket implements stack.NetworkDispatcher.DeliverOutboundPacket. 63 func (e *Endpoint) DeliverOutboundPacket(remote, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 64 if !e.dispatchGate.Enter() { 65 return 66 } 67 e.dispatcher.DeliverOutboundPacket(remote, local, protocol, pkt) 68 e.dispatchGate.Leave() 69 } 70 71 // Attach implements stack.LinkEndpoint.Attach. It saves the dispatcher and 72 // registers with the lower endpoint as its dispatcher so that "e" is called 73 // for inbound packets. 74 func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) { 75 e.dispatcher = dispatcher 76 e.lower.Attach(e) 77 } 78 79 // IsAttached implements stack.LinkEndpoint.IsAttached. 80 func (e *Endpoint) IsAttached() bool { 81 return e.dispatcher != nil 82 } 83 84 // MTU implements stack.LinkEndpoint.MTU. It just forwards the request to the 85 // lower endpoint. 86 func (e *Endpoint) MTU() uint32 { 87 return e.lower.MTU() 88 } 89 90 // Capabilities implements stack.LinkEndpoint.Capabilities. It just forwards the 91 // request to the lower endpoint. 92 func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { 93 return e.lower.Capabilities() 94 } 95 96 // MaxHeaderLength implements stack.LinkEndpoint.MaxHeaderLength. It just 97 // forwards the request to the lower endpoint. 98 func (e *Endpoint) MaxHeaderLength() uint16 { 99 return e.lower.MaxHeaderLength() 100 } 101 102 // LinkAddress implements stack.LinkEndpoint.LinkAddress. It just forwards the 103 // request to the lower endpoint. 104 func (e *Endpoint) LinkAddress() tcpip.LinkAddress { 105 return e.lower.LinkAddress() 106 } 107 108 // WritePacket implements stack.LinkEndpoint.WritePacket. It is called by 109 // higher-level protocols to write packets. It only forwards packets to the 110 // lower endpoint if Wait or WaitWrite haven't been called. 111 func (e *Endpoint) WritePacket(r stack.RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error { 112 if !e.writeGate.Enter() { 113 return nil 114 } 115 116 err := e.lower.WritePacket(r, protocol, pkt) 117 e.writeGate.Leave() 118 return err 119 } 120 121 // WritePackets implements stack.LinkEndpoint.WritePackets. It is called by 122 // higher-level protocols to write packets. It only forwards packets to the 123 // lower endpoint if Wait or WaitWrite haven't been called. 124 func (e *Endpoint) WritePackets(r stack.RouteInfo, pkts stack.PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, tcpip.Error) { 125 if !e.writeGate.Enter() { 126 return pkts.Len(), nil 127 } 128 129 n, err := e.lower.WritePackets(r, pkts, protocol) 130 e.writeGate.Leave() 131 return n, err 132 } 133 134 // WaitWrite prevents new calls to WritePacket from reaching the lower endpoint, 135 // and waits for inflight ones to finish before returning. 136 func (e *Endpoint) WaitWrite() { 137 e.writeGate.Close() 138 } 139 140 // WaitDispatch prevents new calls to DeliverNetworkPacket from reaching the 141 // actual dispatcher, and waits for inflight ones to finish before returning. 142 func (e *Endpoint) WaitDispatch() { 143 e.dispatchGate.Close() 144 } 145 146 // Wait implements stack.LinkEndpoint.Wait. 147 func (e *Endpoint) Wait() {} 148 149 // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType. 150 func (e *Endpoint) ARPHardwareType() header.ARPHardwareType { 151 return e.lower.ARPHardwareType() 152 } 153 154 // AddHeader implements stack.LinkEndpoint.AddHeader. 155 func (e *Endpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 156 e.lower.AddHeader(local, remote, protocol, pkt) 157 }