github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/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 implemention 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  	"github.com/google/netstack/tcpip"
    25  	"github.com/google/netstack/tcpip/buffer"
    26  	"github.com/google/netstack/tcpip/header"
    27  	"github.com/google/netstack/tcpip/stack"
    28  )
    29  
    30  type endpoint struct {
    31  	dispatcher stack.NetworkDispatcher
    32  }
    33  
    34  // New creates a new loopback endpoint. This link-layer endpoint just turns
    35  // outbound packets into inbound packets.
    36  func New() stack.LinkEndpoint {
    37  	return &endpoint{}
    38  }
    39  
    40  // Attach implements stack.LinkEndpoint.Attach. It just saves the stack network-
    41  // layer dispatcher for later use when packets need to be dispatched.
    42  func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) {
    43  	e.dispatcher = dispatcher
    44  }
    45  
    46  // IsAttached implements stack.LinkEndpoint.IsAttached.
    47  func (e *endpoint) IsAttached() bool {
    48  	return e.dispatcher != nil
    49  }
    50  
    51  // MTU implements stack.LinkEndpoint.MTU. It returns a constant that matches the
    52  // linux loopback interface.
    53  func (*endpoint) MTU() uint32 {
    54  	return 65536
    55  }
    56  
    57  // Capabilities implements stack.LinkEndpoint.Capabilities. Loopback advertises
    58  // itself as supporting checksum offload, but in reality it's just omitted.
    59  func (*endpoint) Capabilities() stack.LinkEndpointCapabilities {
    60  	return stack.CapabilityRXChecksumOffload | stack.CapabilityTXChecksumOffload | stack.CapabilitySaveRestore | stack.CapabilityLoopback
    61  }
    62  
    63  // MaxHeaderLength implements stack.LinkEndpoint.MaxHeaderLength. Given that the
    64  // loopback interface doesn't have a header, it just returns 0.
    65  func (*endpoint) MaxHeaderLength() uint16 {
    66  	return 0
    67  }
    68  
    69  // LinkAddress returns the link address of this endpoint.
    70  func (*endpoint) LinkAddress() tcpip.LinkAddress {
    71  	return ""
    72  }
    73  
    74  // Wait implements stack.LinkEndpoint.Wait.
    75  func (*endpoint) Wait() {}
    76  
    77  // WritePacket implements stack.LinkEndpoint.WritePacket. It delivers outbound
    78  // packets to the network-layer dispatcher.
    79  func (e *endpoint) WritePacket(_ *stack.Route, _ *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) *tcpip.Error {
    80  	views := make([]buffer.View, 1, 1+len(pkt.Data.Views()))
    81  	views[0] = pkt.Header.View()
    82  	views = append(views, pkt.Data.Views()...)
    83  
    84  	// Because we're immediately turning around and writing the packet back
    85  	// to the rx path, we intentionally don't preserve the remote and local
    86  	// link addresses from the stack.Route we're passed.
    87  	e.dispatcher.DeliverNetworkPacket(e, "" /* remote */, "" /* local */, protocol, tcpip.PacketBuffer{
    88  		Data: buffer.NewVectorisedView(len(views[0])+pkt.Data.Size(), views),
    89  	})
    90  
    91  	return nil
    92  }
    93  
    94  // WritePackets implements stack.LinkEndpoint.WritePackets.
    95  func (e *endpoint) WritePackets(_ *stack.Route, _ *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
    96  	panic("not implemented")
    97  }
    98  
    99  // WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
   100  func (e *endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
   101  	// Reject the packet if it's shorter than an ethernet header.
   102  	if vv.Size() < header.EthernetMinimumSize {
   103  		return tcpip.ErrBadAddress
   104  	}
   105  
   106  	// There should be an ethernet header at the beginning of vv.
   107  	linkHeader := header.Ethernet(vv.First()[:header.EthernetMinimumSize])
   108  	vv.TrimFront(len(linkHeader))
   109  	e.dispatcher.DeliverNetworkPacket(e, "" /* remote */, "" /* local */, linkHeader.Type(), tcpip.PacketBuffer{
   110  		Data:       vv,
   111  		LinkHeader: buffer.View(linkHeader),
   112  	})
   113  
   114  	return nil
   115  }