inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/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  	"inet.af/netstack/sync"
    24  	"inet.af/netstack/tcpip"
    25  	"inet.af/netstack/tcpip/header"
    26  	"inet.af/netstack/tcpip/stack"
    27  )
    28  
    29  // PacketInfo holds all the information about an outbound packet.
    30  type PacketInfo struct {
    31  	Pkt *stack.PacketBuffer
    32  
    33  	// TODO(https://gvisor.dev/issue/6537): Remove these fields.
    34  	Proto tcpip.NetworkProtocolNumber
    35  	Route stack.RouteInfo
    36  }
    37  
    38  // Notification is the interface for receiving notification from the packet
    39  // queue.
    40  type Notification interface {
    41  	// WriteNotify will be called when a write happens to the queue.
    42  	WriteNotify()
    43  }
    44  
    45  // NotificationHandle is an opaque handle to the registered notification target.
    46  // It can be used to unregister the notification when no longer interested.
    47  //
    48  // +stateify savable
    49  type NotificationHandle struct {
    50  	n Notification
    51  }
    52  
    53  type queue struct {
    54  	// c is the outbound packet channel.
    55  	c chan PacketInfo
    56  	// mu protects fields below.
    57  	mu     sync.RWMutex
    58  	notify []*NotificationHandle
    59  }
    60  
    61  func (q *queue) Close() {
    62  	close(q.c)
    63  }
    64  
    65  func (q *queue) Read() (PacketInfo, bool) {
    66  	select {
    67  	case p := <-q.c:
    68  		return p, true
    69  	default:
    70  		return PacketInfo{}, false
    71  	}
    72  }
    73  
    74  func (q *queue) ReadContext(ctx context.Context) (PacketInfo, bool) {
    75  	select {
    76  	case pkt := <-q.c:
    77  		return pkt, true
    78  	case <-ctx.Done():
    79  		return PacketInfo{}, false
    80  	}
    81  }
    82  
    83  func (q *queue) Write(p PacketInfo) bool {
    84  	// q holds the PacketBuffer.
    85  
    86  	// Ideally, Write() should take a reference here, since it is adding
    87  	// the underlying PacketBuffer to the channel. However, in practice,
    88  	// calls to Read() are not necessarily symetric with calls
    89  	// to Write() (e.g writing to this endpoint and then exiting). This
    90  	// causes tests and analyzers to detect erroneous "leaks" for expected
    91  	// behavior. To prevent this, we allow the refcount to go to zero, and
    92  	// make a call to  PreserveObject(), which prevents the PacketBuffer
    93  	// pooling implementation from reclaiming this instance, even when
    94  	// the refcount goes to zero.
    95  	p.Pkt.PreserveObject()
    96  	wrote := false
    97  	select {
    98  	case q.c <- p:
    99  		wrote = true
   100  	default:
   101  	}
   102  	q.mu.Lock()
   103  	notify := q.notify
   104  	q.mu.Unlock()
   105  
   106  	if wrote {
   107  		// Send notification outside of lock.
   108  		for _, h := range notify {
   109  			h.n.WriteNotify()
   110  		}
   111  	}
   112  	return wrote
   113  }
   114  
   115  func (q *queue) Num() int {
   116  	return len(q.c)
   117  }
   118  
   119  func (q *queue) AddNotify(notify Notification) *NotificationHandle {
   120  	q.mu.Lock()
   121  	defer q.mu.Unlock()
   122  	h := &NotificationHandle{n: notify}
   123  	q.notify = append(q.notify, h)
   124  	return h
   125  }
   126  
   127  func (q *queue) RemoveNotify(handle *NotificationHandle) {
   128  	q.mu.Lock()
   129  	defer q.mu.Unlock()
   130  	// Make a copy, since we reads the array outside of lock when notifying.
   131  	notify := make([]*NotificationHandle, 0, len(q.notify))
   132  	for _, h := range q.notify {
   133  		if h != handle {
   134  			notify = append(notify, h)
   135  		}
   136  	}
   137  	q.notify = notify
   138  }
   139  
   140  var _ stack.LinkEndpoint = (*Endpoint)(nil)
   141  var _ stack.GSOEndpoint = (*Endpoint)(nil)
   142  
   143  // Endpoint is link layer endpoint that stores outbound packets in a channel
   144  // and allows injection of inbound packets.
   145  type Endpoint struct {
   146  	dispatcher         stack.NetworkDispatcher
   147  	mtu                uint32
   148  	linkAddr           tcpip.LinkAddress
   149  	LinkEPCapabilities stack.LinkEndpointCapabilities
   150  	SupportedGSOKind   stack.SupportedGSO
   151  
   152  	// Outbound packet queue.
   153  	q *queue
   154  }
   155  
   156  // New creates a new channel endpoint.
   157  func New(size int, mtu uint32, linkAddr tcpip.LinkAddress) *Endpoint {
   158  	return &Endpoint{
   159  		q: &queue{
   160  			c: make(chan PacketInfo, size),
   161  		},
   162  		mtu:      mtu,
   163  		linkAddr: linkAddr,
   164  	}
   165  }
   166  
   167  // Close closes e. Further packet injections will panic. Reads continue to
   168  // succeed until all packets are read.
   169  func (e *Endpoint) Close() {
   170  	e.q.Close()
   171  }
   172  
   173  // Read does non-blocking read one packet from the outbound packet queue.
   174  func (e *Endpoint) Read() (PacketInfo, bool) {
   175  	return e.q.Read()
   176  }
   177  
   178  // ReadContext does blocking read for one packet from the outbound packet queue.
   179  // It can be cancelled by ctx, and in this case, it returns false.
   180  func (e *Endpoint) ReadContext(ctx context.Context) (PacketInfo, bool) {
   181  	return e.q.ReadContext(ctx)
   182  }
   183  
   184  // Drain removes all outbound packets from the channel and counts them.
   185  func (e *Endpoint) Drain() int {
   186  	c := 0
   187  	for {
   188  		if _, ok := e.Read(); !ok {
   189  			return c
   190  		}
   191  		c++
   192  	}
   193  }
   194  
   195  // NumQueued returns the number of packet queued for outbound.
   196  func (e *Endpoint) NumQueued() int {
   197  	return e.q.Num()
   198  }
   199  
   200  // InjectInbound injects an inbound packet.
   201  func (e *Endpoint) InjectInbound(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
   202  	e.InjectLinkAddr(protocol, "", pkt)
   203  }
   204  
   205  // InjectLinkAddr injects an inbound packet with a remote link address.
   206  func (e *Endpoint) InjectLinkAddr(protocol tcpip.NetworkProtocolNumber, remote tcpip.LinkAddress, pkt *stack.PacketBuffer) {
   207  	e.dispatcher.DeliverNetworkPacket(remote, "" /* local */, protocol, pkt)
   208  }
   209  
   210  // Attach saves the stack network-layer dispatcher for use later when packets
   211  // are injected.
   212  func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) {
   213  	e.dispatcher = dispatcher
   214  }
   215  
   216  // IsAttached implements stack.LinkEndpoint.IsAttached.
   217  func (e *Endpoint) IsAttached() bool {
   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  // WritePacket stores outbound packets into the channel.
   254  func (e *Endpoint) WritePacket(r stack.RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) tcpip.Error {
   255  	p := PacketInfo{
   256  		Pkt:   pkt,
   257  		Proto: protocol,
   258  		Route: r,
   259  	}
   260  
   261  	// Write returns false if the queue is full. A full queue is not an error
   262  	// from the perspective of a LinkEndpoint so we ignore Write's return
   263  	// value and always return nil from this method.
   264  	_ = e.q.Write(p)
   265  
   266  	return nil
   267  }
   268  
   269  // WritePackets stores outbound packets into the channel.
   270  func (e *Endpoint) WritePackets(r stack.RouteInfo, pkts stack.PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
   271  	n := 0
   272  	for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
   273  		p := PacketInfo{
   274  			Pkt:   pkt,
   275  			Proto: protocol,
   276  			Route: r,
   277  		}
   278  
   279  		if !e.q.Write(p) {
   280  			break
   281  		}
   282  		n++
   283  	}
   284  
   285  	return n, nil
   286  }
   287  
   288  // Wait implements stack.LinkEndpoint.Wait.
   289  func (*Endpoint) Wait() {}
   290  
   291  // AddNotify adds a notification target for receiving event about outgoing
   292  // packets.
   293  func (e *Endpoint) AddNotify(notify Notification) *NotificationHandle {
   294  	return e.q.AddNotify(notify)
   295  }
   296  
   297  // RemoveNotify removes handle from the list of notification targets.
   298  func (e *Endpoint) RemoveNotify(handle *NotificationHandle) {
   299  	e.q.RemoveNotify(handle)
   300  }
   301  
   302  // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType.
   303  func (*Endpoint) ARPHardwareType() header.ARPHardwareType {
   304  	return header.ARPHardwareNone
   305  }
   306  
   307  // AddHeader implements stack.LinkEndpoint.AddHeader.
   308  func (*Endpoint) AddHeader(tcpip.LinkAddress, tcpip.LinkAddress, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) {
   309  }
   310  
   311  // WriteRawPacket implements stack.LinkEndpoint.
   312  func (e *Endpoint) WriteRawPacket(pkt *stack.PacketBuffer) tcpip.Error {
   313  	p := PacketInfo{
   314  		Pkt:   pkt,
   315  		Proto: pkt.NetworkProtocolNumber,
   316  	}
   317  
   318  	// Write returns false if the queue is full. A full queue is not an error
   319  	// from the perspective of a LinkEndpoint so we ignore Write's return
   320  	// value and always return nil from this method.
   321  	_ = e.q.Write(p)
   322  
   323  	return nil
   324  }