github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/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 "context" 22 23 "github.com/SagerNet/gvisor/pkg/sync" 24 "github.com/SagerNet/gvisor/pkg/tcpip" 25 "github.com/SagerNet/gvisor/pkg/tcpip/header" 26 "github.com/SagerNet/gvisor/pkg/tcpip/stack" 27 ) 28 29 // PacketInfo holds all the information about an outbound packet. 30 type PacketInfo struct { 31 Pkt *stack.PacketBuffer 32 Proto tcpip.NetworkProtocolNumber 33 Route stack.RouteInfo 34 } 35 36 // Notification is the interface for receiving notification from the packet 37 // queue. 38 type Notification interface { 39 // WriteNotify will be called when a write happens to the queue. 40 WriteNotify() 41 } 42 43 // NotificationHandle is an opaque handle to the registered notification target. 44 // It can be used to unregister the notification when no longer interested. 45 // 46 // +stateify savable 47 type NotificationHandle struct { 48 n Notification 49 } 50 51 type queue struct { 52 // c is the outbound packet channel. 53 c chan PacketInfo 54 // mu protects fields below. 55 mu sync.RWMutex 56 notify []*NotificationHandle 57 } 58 59 func (q *queue) Close() { 60 close(q.c) 61 } 62 63 func (q *queue) Read() (PacketInfo, bool) { 64 select { 65 case p := <-q.c: 66 return p, true 67 default: 68 return PacketInfo{}, false 69 } 70 } 71 72 func (q *queue) ReadContext(ctx context.Context) (PacketInfo, bool) { 73 select { 74 case pkt := <-q.c: 75 return pkt, true 76 case <-ctx.Done(): 77 return PacketInfo{}, false 78 } 79 } 80 81 func (q *queue) Write(p PacketInfo) bool { 82 wrote := false 83 select { 84 case q.c <- p: 85 wrote = true 86 default: 87 } 88 q.mu.Lock() 89 notify := q.notify 90 q.mu.Unlock() 91 92 if wrote { 93 // Send notification outside of lock. 94 for _, h := range notify { 95 h.n.WriteNotify() 96 } 97 } 98 return wrote 99 } 100 101 func (q *queue) Num() int { 102 return len(q.c) 103 } 104 105 func (q *queue) AddNotify(notify Notification) *NotificationHandle { 106 q.mu.Lock() 107 defer q.mu.Unlock() 108 h := &NotificationHandle{n: notify} 109 q.notify = append(q.notify, h) 110 return h 111 } 112 113 func (q *queue) RemoveNotify(handle *NotificationHandle) { 114 q.mu.Lock() 115 defer q.mu.Unlock() 116 // Make a copy, since we reads the array outside of lock when notifying. 117 notify := make([]*NotificationHandle, 0, len(q.notify)) 118 for _, h := range q.notify { 119 if h != handle { 120 notify = append(notify, h) 121 } 122 } 123 q.notify = notify 124 } 125 126 var _ stack.LinkEndpoint = (*Endpoint)(nil) 127 var _ stack.GSOEndpoint = (*Endpoint)(nil) 128 129 // Endpoint is link layer endpoint that stores outbound packets in a channel 130 // and allows injection of inbound packets. 131 type Endpoint struct { 132 dispatcher stack.NetworkDispatcher 133 mtu uint32 134 linkAddr tcpip.LinkAddress 135 LinkEPCapabilities stack.LinkEndpointCapabilities 136 SupportedGSOKind stack.SupportedGSO 137 138 // Outbound packet queue. 139 q *queue 140 } 141 142 // New creates a new channel endpoint. 143 func New(size int, mtu uint32, linkAddr tcpip.LinkAddress) *Endpoint { 144 return &Endpoint{ 145 q: &queue{ 146 c: make(chan PacketInfo, size), 147 }, 148 mtu: mtu, 149 linkAddr: linkAddr, 150 } 151 } 152 153 // Close closes e. Further packet injections will panic. Reads continue to 154 // succeed until all packets are read. 155 func (e *Endpoint) Close() { 156 e.q.Close() 157 } 158 159 // Read does non-blocking read one packet from the outbound packet queue. 160 func (e *Endpoint) Read() (PacketInfo, bool) { 161 return e.q.Read() 162 } 163 164 // ReadContext does blocking read for one packet from the outbound packet queue. 165 // It can be cancelled by ctx, and in this case, it returns false. 166 func (e *Endpoint) ReadContext(ctx context.Context) (PacketInfo, bool) { 167 return e.q.ReadContext(ctx) 168 } 169 170 // Drain removes all outbound packets from the channel and counts them. 171 func (e *Endpoint) Drain() int { 172 c := 0 173 for { 174 if _, ok := e.Read(); !ok { 175 return c 176 } 177 c++ 178 } 179 } 180 181 // NumQueued returns the number of packet queued for outbound. 182 func (e *Endpoint) NumQueued() int { 183 return e.q.Num() 184 } 185 186 // InjectInbound injects an inbound packet. 187 func (e *Endpoint) InjectInbound(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 188 e.InjectLinkAddr(protocol, "", pkt) 189 } 190 191 // InjectLinkAddr injects an inbound packet with a remote link address. 192 func (e *Endpoint) InjectLinkAddr(protocol tcpip.NetworkProtocolNumber, remote tcpip.LinkAddress, pkt *stack.PacketBuffer) { 193 e.dispatcher.DeliverNetworkPacket(remote, "" /* local */, protocol, pkt) 194 } 195 196 // Attach saves the stack network-layer dispatcher for use later when packets 197 // are injected. 198 func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) { 199 e.dispatcher = dispatcher 200 } 201 202 // IsAttached implements stack.LinkEndpoint.IsAttached. 203 func (e *Endpoint) IsAttached() bool { 204 return e.dispatcher != nil 205 } 206 207 // MTU implements stack.LinkEndpoint.MTU. It returns the value initialized 208 // during construction. 209 func (e *Endpoint) MTU() uint32 { 210 return e.mtu 211 } 212 213 // Capabilities implements stack.LinkEndpoint.Capabilities. 214 func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { 215 return e.LinkEPCapabilities 216 } 217 218 // GSOMaxSize implements stack.GSOEndpoint. 219 func (*Endpoint) GSOMaxSize() uint32 { 220 return 1 << 15 221 } 222 223 // SupportedGSO implements stack.GSOEndpoint. 224 func (e *Endpoint) SupportedGSO() stack.SupportedGSO { 225 return e.SupportedGSOKind 226 } 227 228 // MaxHeaderLength returns the maximum size of the link layer header. Given it 229 // doesn't have a header, it just returns 0. 230 func (*Endpoint) MaxHeaderLength() uint16 { 231 return 0 232 } 233 234 // LinkAddress returns the link address of this endpoint. 235 func (e *Endpoint) LinkAddress() tcpip.LinkAddress { 236 return e.linkAddr 237 } 238 239 // WritePacket stores outbound packets into the channel. 240 func (e *Endpoint) WritePacket(r stack.RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error { 241 p := PacketInfo{ 242 Pkt: pkt, 243 Proto: protocol, 244 Route: r, 245 } 246 247 e.q.Write(p) 248 249 return nil 250 } 251 252 // WritePackets stores outbound packets into the channel. 253 func (e *Endpoint) WritePackets(r stack.RouteInfo, pkts stack.PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, tcpip.Error) { 254 n := 0 255 for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() { 256 p := PacketInfo{ 257 Pkt: pkt, 258 Proto: protocol, 259 Route: r, 260 } 261 262 if !e.q.Write(p) { 263 break 264 } 265 n++ 266 } 267 268 return n, nil 269 } 270 271 // Wait implements stack.LinkEndpoint.Wait. 272 func (*Endpoint) Wait() {} 273 274 // AddNotify adds a notification target for receiving event about outgoing 275 // packets. 276 func (e *Endpoint) AddNotify(notify Notification) *NotificationHandle { 277 return e.q.AddNotify(notify) 278 } 279 280 // RemoveNotify removes handle from the list of notification targets. 281 func (e *Endpoint) RemoveNotify(handle *NotificationHandle) { 282 e.q.RemoveNotify(handle) 283 } 284 285 // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType. 286 func (*Endpoint) ARPHardwareType() header.ARPHardwareType { 287 return header.ARPHardwareNone 288 } 289 290 // AddHeader implements stack.LinkEndpoint.AddHeader. 291 func (*Endpoint) AddHeader(tcpip.LinkAddress, tcpip.LinkAddress, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) { 292 }