github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/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/google/netstack/gate" 26 "github.com/google/netstack/tcpip" 27 "github.com/google/netstack/tcpip/buffer" 28 "github.com/google/netstack/tcpip/stack" 29 ) 30 31 // Endpoint is a waitable link-layer endpoint. 32 type Endpoint struct { 33 dispatchGate gate.Gate 34 dispatcher stack.NetworkDispatcher 35 36 writeGate gate.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(linkEP stack.LinkEndpoint, remote, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) { 54 if !e.dispatchGate.Enter() { 55 return 56 } 57 58 e.dispatcher.DeliverNetworkPacket(e, remote, local, protocol, pkt) 59 e.dispatchGate.Leave() 60 } 61 62 // Attach implements stack.LinkEndpoint.Attach. It saves the dispatcher and 63 // registers with the lower endpoint as its dispatcher so that "e" is called 64 // for inbound packets. 65 func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) { 66 e.dispatcher = dispatcher 67 e.lower.Attach(e) 68 } 69 70 // IsAttached implements stack.LinkEndpoint.IsAttached. 71 func (e *Endpoint) IsAttached() bool { 72 return e.dispatcher != nil 73 } 74 75 // MTU implements stack.LinkEndpoint.MTU. It just forwards the request to the 76 // lower endpoint. 77 func (e *Endpoint) MTU() uint32 { 78 return e.lower.MTU() 79 } 80 81 // Capabilities implements stack.LinkEndpoint.Capabilities. It just forwards the 82 // request to the lower endpoint. 83 func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { 84 return e.lower.Capabilities() 85 } 86 87 // MaxHeaderLength implements stack.LinkEndpoint.MaxHeaderLength. It just 88 // forwards the request to the lower endpoint. 89 func (e *Endpoint) MaxHeaderLength() uint16 { 90 return e.lower.MaxHeaderLength() 91 } 92 93 // LinkAddress implements stack.LinkEndpoint.LinkAddress. It just forwards the 94 // request to the lower endpoint. 95 func (e *Endpoint) LinkAddress() tcpip.LinkAddress { 96 return e.lower.LinkAddress() 97 } 98 99 // WritePacket implements stack.LinkEndpoint.WritePacket. It is called by 100 // higher-level protocols to write packets. It only forwards packets to the 101 // lower endpoint if Wait or WaitWrite haven't been called. 102 func (e *Endpoint) WritePacket(r *stack.Route, gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) *tcpip.Error { 103 if !e.writeGate.Enter() { 104 return nil 105 } 106 107 err := e.lower.WritePacket(r, gso, protocol, pkt) 108 e.writeGate.Leave() 109 return err 110 } 111 112 // WritePackets implements stack.LinkEndpoint.WritePackets. It is called by 113 // higher-level protocols to write packets. It only forwards packets to the 114 // lower endpoint if Wait or WaitWrite haven't been called. 115 func (e *Endpoint) WritePackets(r *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) { 116 if !e.writeGate.Enter() { 117 return len(hdrs), nil 118 } 119 120 n, err := e.lower.WritePackets(r, gso, hdrs, payload, protocol) 121 e.writeGate.Leave() 122 return n, err 123 } 124 125 // WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket. 126 func (e *Endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error { 127 if !e.writeGate.Enter() { 128 return nil 129 } 130 131 err := e.lower.WriteRawPacket(vv) 132 e.writeGate.Leave() 133 return err 134 } 135 136 // WaitWrite prevents new calls to WritePacket from reaching the lower endpoint, 137 // and waits for inflight ones to finish before returning. 138 func (e *Endpoint) WaitWrite() { 139 e.writeGate.Close() 140 } 141 142 // WaitDispatch prevents new calls to DeliverNetworkPacket from reaching the 143 // actual dispatcher, and waits for inflight ones to finish before returning. 144 func (e *Endpoint) WaitDispatch() { 145 e.dispatchGate.Close() 146 } 147 148 // Wait implements stack.LinkEndpoint.Wait. 149 func (e *Endpoint) Wait() {}