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