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