github.com/noisysockets/netstack@v0.6.0/pkg/tcpip/link/loopback/loopback.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 loopback provides the implementation of loopback data-link layer
    16  // endpoints. Such endpoints just turn outbound packets into inbound ones.
    17  //
    18  // Loopback endpoints can be used in the networking stack by calling New() to
    19  // create a new endpoint, and then passing it as an argument to
    20  // Stack.CreateNIC().
    21  package loopback
    22  
    23  import (
    24  	"sync"
    25  
    26  	"github.com/noisysockets/netstack/pkg/tcpip"
    27  	"github.com/noisysockets/netstack/pkg/tcpip/header"
    28  	"github.com/noisysockets/netstack/pkg/tcpip/stack"
    29  )
    30  
    31  type endpoint struct {
    32  	mu sync.RWMutex
    33  	// +checklocks:mu
    34  	dispatcher stack.NetworkDispatcher
    35  }
    36  
    37  // New creates a new loopback endpoint. This link-layer endpoint just turns
    38  // outbound packets into inbound packets.
    39  func New() stack.LinkEndpoint {
    40  	return &endpoint{}
    41  }
    42  
    43  // Attach implements stack.LinkEndpoint.Attach. It just saves the stack network-
    44  // layer dispatcher for later use when packets need to be dispatched.
    45  func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
    46  	e.mu.Lock()
    47  	defer e.mu.Unlock()
    48  	e.dispatcher = dispatcher
    49  }
    50  
    51  // IsAttached implements stack.LinkEndpoint.IsAttached.
    52  func (e *endpoint) IsAttached() bool {
    53  	e.mu.RLock()
    54  	defer e.mu.RUnlock()
    55  	return e.dispatcher != nil
    56  }
    57  
    58  // MTU implements stack.LinkEndpoint.MTU. It returns a constant that matches the
    59  // linux loopback interface.
    60  func (*endpoint) MTU() uint32 {
    61  	return 65536
    62  }
    63  
    64  // Capabilities implements stack.LinkEndpoint.Capabilities. Loopback advertises
    65  // itself as supporting checksum offload, but in reality it's just omitted.
    66  func (*endpoint) Capabilities() stack.LinkEndpointCapabilities {
    67  	return stack.CapabilityRXChecksumOffload | stack.CapabilityTXChecksumOffload | stack.CapabilitySaveRestore | stack.CapabilityLoopback
    68  }
    69  
    70  // MaxHeaderLength implements stack.LinkEndpoint.MaxHeaderLength. Given that the
    71  // loopback interface doesn't have a header, it just returns 0.
    72  func (*endpoint) MaxHeaderLength() uint16 {
    73  	return 0
    74  }
    75  
    76  // LinkAddress returns the link address of this endpoint.
    77  func (*endpoint) LinkAddress() tcpip.LinkAddress {
    78  	return ""
    79  }
    80  
    81  // Wait implements stack.LinkEndpoint.Wait.
    82  func (*endpoint) Wait() {}
    83  
    84  // WritePackets implements stack.LinkEndpoint.WritePackets. If the endpoint is
    85  // not attached, the packets are not delivered.
    86  func (e *endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) {
    87  	e.mu.RLock()
    88  	d := e.dispatcher
    89  	e.mu.RUnlock()
    90  	for _, pkt := range pkts.AsSlice() {
    91  		// In order to properly loop back to the inbound side we must create a
    92  		// fresh packet that only contains the underlying payload with no headers
    93  		// or struct fields set.
    94  		newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
    95  			Payload: pkt.ToBuffer(),
    96  		})
    97  		if d != nil {
    98  			d.DeliverNetworkPacket(pkt.NetworkProtocolNumber, newPkt)
    99  		}
   100  		newPkt.DecRef()
   101  	}
   102  	return pkts.Len(), nil
   103  }
   104  
   105  // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType.
   106  func (*endpoint) ARPHardwareType() header.ARPHardwareType {
   107  	return header.ARPHardwareLoopback
   108  }
   109  
   110  // AddHeader implements stack.LinkEndpoint.
   111  func (*endpoint) AddHeader(*stack.PacketBuffer) {}
   112  
   113  // ParseHeader implements stack.LinkEndpoint.
   114  func (*endpoint) ParseHeader(*stack.PacketBuffer) bool { return true }