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 }