github.com/vpnishe/netstack@v1.10.6/tcpip/link/channel/channel.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 channel provides the implemention of channel-based data-link layer 16 // endpoints. Such endpoints allow injection of inbound packets and store 17 // outbound packets in a channel. 18 package channel 19 20 import ( 21 "errors" 22 23 "github.com/vpnishe/netstack/tcpip" 24 "github.com/vpnishe/netstack/tcpip/buffer" 25 "github.com/vpnishe/netstack/tcpip/stack" 26 ) 27 28 // PacketInfo holds all the information about an outbound packet. 29 type PacketInfo struct { 30 Pkt tcpip.PacketBuffer 31 Proto tcpip.NetworkProtocolNumber 32 GSO *stack.GSO 33 } 34 35 // Endpoint is link layer endpoint that stores outbound packets in a channel 36 // and allows injection of inbound packets. 37 type Endpoint struct { 38 dispatcher stack.NetworkDispatcher 39 mtu uint32 40 linkAddr tcpip.LinkAddress 41 GSO bool 42 43 // C is where outbound packets are queued. 44 ch chan PacketInfo 45 } 46 47 // New creates a new channel endpoint. 48 func New(size int, mtu uint32, linkAddr tcpip.LinkAddress) *Endpoint { 49 return &Endpoint{ 50 ch: make(chan PacketInfo, size), 51 mtu: mtu, 52 linkAddr: linkAddr, 53 } 54 } 55 56 // Drain removes all outbound packets from the channel and counts them. 57 func (e *Endpoint) Drain() int { 58 59 if e.ch == nil { 60 return 0 61 } 62 63 c := 0 64 for { 65 select { 66 case <-e.ch: 67 c++ 68 default: 69 return c 70 } 71 } 72 } 73 74 func (e *Endpoint) Read() (*PacketInfo, error) { 75 76 if e.ch == nil { 77 return nil, errors.New("link channel is closed") 78 } 79 80 pkgInfo, ok := <-e.ch 81 if !ok { 82 return nil, errors.New("link channel closed") 83 } 84 return &pkgInfo, nil 85 86 } 87 88 func (e *Endpoint) Close() { 89 if e.ch == nil { 90 return 91 } 92 ch := e.ch 93 e.ch = nil 94 close(ch) 95 96 } 97 98 // InjectInbound injects an inbound packet. 99 func (e *Endpoint) InjectInbound(protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) { 100 e.InjectLinkAddr(protocol, "", pkt) 101 } 102 103 // InjectLinkAddr injects an inbound packet with a remote link address. 104 func (e *Endpoint) InjectLinkAddr(protocol tcpip.NetworkProtocolNumber, remote tcpip.LinkAddress, pkt tcpip.PacketBuffer) { 105 e.dispatcher.DeliverNetworkPacket(e, remote, "" /* local */, protocol, pkt) 106 } 107 108 // Attach saves the stack network-layer dispatcher for use later when packets 109 // are injected. 110 func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) { 111 e.dispatcher = dispatcher 112 } 113 114 // IsAttached implements stack.LinkEndpoint.IsAttached. 115 func (e *Endpoint) IsAttached() bool { 116 return e.dispatcher != nil 117 } 118 119 // MTU implements stack.LinkEndpoint.MTU. It returns the value initialized 120 // during construction. 121 func (e *Endpoint) MTU() uint32 { 122 return e.mtu 123 } 124 125 // Capabilities implements stack.LinkEndpoint.Capabilities. 126 func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { 127 caps := stack.LinkEndpointCapabilities(0) 128 if e.GSO { 129 caps |= stack.CapabilityHardwareGSO 130 } 131 return caps 132 } 133 134 // GSOMaxSize returns the maximum GSO packet size. 135 func (*Endpoint) GSOMaxSize() uint32 { 136 return 1 << 15 137 } 138 139 // MaxHeaderLength returns the maximum size of the link layer header. Given it 140 // doesn't have a header, it just returns 0. 141 func (*Endpoint) MaxHeaderLength() uint16 { 142 return 0 143 } 144 145 // LinkAddress returns the link address of this endpoint. 146 func (e *Endpoint) LinkAddress() tcpip.LinkAddress { 147 return e.linkAddr 148 } 149 150 // WritePacket stores outbound packets into the channel. 151 func (e *Endpoint) WritePacket(_ *stack.Route, gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) *tcpip.Error { 152 153 if e.ch == nil { 154 return tcpip.ErrBadLinkEndpoint 155 } 156 157 p := PacketInfo{ 158 Pkt: pkt, 159 Proto: protocol, 160 GSO: gso, 161 } 162 163 select { 164 case e.ch <- p: 165 default: 166 } 167 168 return nil 169 } 170 171 // WritePackets stores outbound packets into the channel. 172 func (e *Endpoint) WritePackets(_ *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) { 173 174 if e.ch == nil { 175 return 0, tcpip.ErrBadLinkEndpoint 176 } 177 178 payloadView := payload.ToView() 179 n := 0 180 packetLoop: 181 for _, hdr := range hdrs { 182 off := hdr.Off 183 size := hdr.Size 184 p := PacketInfo{ 185 Pkt: tcpip.PacketBuffer{ 186 Header: hdr.Hdr, 187 Data: buffer.NewViewFromBytes(payloadView[off : off+size]).ToVectorisedView(), 188 }, 189 Proto: protocol, 190 GSO: gso, 191 } 192 193 select { 194 case e.ch <- p: 195 n++ 196 default: 197 break packetLoop 198 } 199 } 200 201 return n, nil 202 } 203 204 // WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket. 205 func (e *Endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error { 206 if e.ch == nil { 207 return tcpip.ErrBadLinkEndpoint 208 } 209 p := PacketInfo{ 210 Pkt: tcpip.PacketBuffer{Data: vv}, 211 Proto: 0, 212 GSO: nil, 213 } 214 215 select { 216 case e.ch <- p: 217 default: 218 } 219 220 return nil 221 } 222 223 // Wait implements stack.LinkEndpoint.Wait. 224 func (*Endpoint) Wait() {}