github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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/metacubex/gvisor/pkg/sync" 26 "github.com/metacubex/gvisor/pkg/tcpip" 27 "github.com/metacubex/gvisor/pkg/tcpip/header" 28 "github.com/metacubex/gvisor/pkg/tcpip/stack" 29 ) 30 31 var _ stack.NetworkDispatcher = (*Endpoint)(nil) 32 var _ stack.LinkEndpoint = (*Endpoint)(nil) 33 34 // Endpoint is a waitable link-layer endpoint. 35 type Endpoint struct { 36 dispatchGate sync.Gate 37 38 mu sync.RWMutex 39 // +checklocks:mu 40 dispatcher stack.NetworkDispatcher 41 42 writeGate sync.Gate 43 lower stack.LinkEndpoint 44 } 45 46 // New creates a new waitable link-layer endpoint. It wraps around another 47 // endpoint and allows the caller to block new write/dispatch calls and wait for 48 // the inflight ones to finish before returning. 49 func New(lower stack.LinkEndpoint) *Endpoint { 50 return &Endpoint{ 51 lower: lower, 52 } 53 } 54 55 // DeliverNetworkPacket implements stack.NetworkDispatcher.DeliverNetworkPacket. 56 // It is called by the link-layer endpoint being wrapped when a packet arrives, 57 // and only forwards to the actual dispatcher if Wait or WaitDispatch haven't 58 // been called. 59 func (e *Endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 60 if !e.dispatchGate.Enter() { 61 return 62 } 63 e.mu.RLock() 64 d := e.dispatcher 65 e.mu.RUnlock() 66 if d != nil { 67 d.DeliverNetworkPacket(protocol, pkt) 68 } 69 e.dispatchGate.Leave() 70 } 71 72 // DeliverLinkPacket implements stack.NetworkDispatcher. 73 func (e *Endpoint) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 74 if !e.dispatchGate.Enter() { 75 return 76 } 77 e.mu.RLock() 78 d := e.dispatcher 79 e.mu.RUnlock() 80 if d != nil { 81 d.DeliverLinkPacket(protocol, pkt) 82 } 83 e.dispatchGate.Leave() 84 } 85 86 // Attach implements stack.LinkEndpoint.Attach. It saves the dispatcher and 87 // registers with the lower endpoint as its dispatcher so that "e" is called 88 // for inbound packets. 89 func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) { 90 e.mu.Lock() 91 e.dispatcher = dispatcher 92 e.mu.Unlock() 93 e.lower.Attach(e) 94 } 95 96 // IsAttached implements stack.LinkEndpoint.IsAttached. 97 func (e *Endpoint) IsAttached() bool { 98 e.mu.RLock() 99 defer e.mu.RUnlock() 100 return e.dispatcher != nil 101 } 102 103 // MTU implements stack.LinkEndpoint.MTU. It just forwards the request to the 104 // lower endpoint. 105 func (e *Endpoint) MTU() uint32 { 106 return e.lower.MTU() 107 } 108 109 // Capabilities implements stack.LinkEndpoint.Capabilities. It just forwards the 110 // request to the lower endpoint. 111 func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { 112 return e.lower.Capabilities() 113 } 114 115 // MaxHeaderLength implements stack.LinkEndpoint.MaxHeaderLength. It just 116 // forwards the request to the lower endpoint. 117 func (e *Endpoint) MaxHeaderLength() uint16 { 118 return e.lower.MaxHeaderLength() 119 } 120 121 // LinkAddress implements stack.LinkEndpoint.LinkAddress. It just forwards the 122 // request to the lower endpoint. 123 func (e *Endpoint) LinkAddress() tcpip.LinkAddress { 124 return e.lower.LinkAddress() 125 } 126 127 // WritePackets implements stack.LinkEndpoint.WritePackets. It is called by 128 // higher-level protocols to write packets. It only forwards packets to the 129 // lower endpoint if Wait or WaitWrite haven't been called. 130 func (e *Endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) { 131 if !e.writeGate.Enter() { 132 return pkts.Len(), nil 133 } 134 135 n, err := e.lower.WritePackets(pkts) 136 e.writeGate.Leave() 137 return n, err 138 } 139 140 // WaitWrite prevents new calls to WritePacket from reaching the lower endpoint, 141 // and waits for inflight ones to finish before returning. 142 func (e *Endpoint) WaitWrite() { 143 e.writeGate.Close() 144 } 145 146 // WaitDispatch prevents new calls to DeliverNetworkPacket from reaching the 147 // actual dispatcher, and waits for inflight ones to finish before returning. 148 func (e *Endpoint) WaitDispatch() { 149 e.dispatchGate.Close() 150 } 151 152 // Wait implements stack.LinkEndpoint.Wait. 153 func (e *Endpoint) Wait() {} 154 155 // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType. 156 func (e *Endpoint) ARPHardwareType() header.ARPHardwareType { 157 return e.lower.ARPHardwareType() 158 } 159 160 // AddHeader implements stack.LinkEndpoint.AddHeader. 161 func (e *Endpoint) AddHeader(pkt *stack.PacketBuffer) { 162 e.lower.AddHeader(pkt) 163 } 164 165 // ParseHeader implements stack.LinkEndpoint.ParseHeader. 166 func (e *Endpoint) ParseHeader(pkt *stack.PacketBuffer) bool { 167 return e.lower.ParseHeader(pkt) 168 }