github.com/noisysockets/netstack@v0.6.0/pkg/tcpip/link/muxed/injectable.go (about) 1 // Copyright 2019 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 muxed provides a muxed link endpoints. 16 package muxed 17 18 import ( 19 "sync" 20 21 "github.com/noisysockets/netstack/pkg/buffer" 22 "github.com/noisysockets/netstack/pkg/tcpip" 23 "github.com/noisysockets/netstack/pkg/tcpip/header" 24 "github.com/noisysockets/netstack/pkg/tcpip/stack" 25 ) 26 27 // InjectableEndpoint is an injectable multi endpoint. The endpoint has 28 // trivial routing rules that determine which InjectableEndpoint a given packet 29 // will be written to. Note that HandleLocal works differently for this 30 // endpoint (see WritePacket). 31 type InjectableEndpoint struct { 32 routes map[tcpip.Address]stack.InjectableLinkEndpoint 33 34 mu sync.RWMutex 35 // +checklocks:mu 36 dispatcher stack.NetworkDispatcher 37 } 38 39 // MTU implements stack.LinkEndpoint. 40 func (m *InjectableEndpoint) MTU() uint32 { 41 minMTU := ^uint32(0) 42 for _, endpoint := range m.routes { 43 if endpointMTU := endpoint.MTU(); endpointMTU < minMTU { 44 minMTU = endpointMTU 45 } 46 } 47 return minMTU 48 } 49 50 // Capabilities implements stack.LinkEndpoint. 51 func (m *InjectableEndpoint) Capabilities() stack.LinkEndpointCapabilities { 52 minCapabilities := stack.LinkEndpointCapabilities(^uint(0)) 53 for _, endpoint := range m.routes { 54 minCapabilities &= endpoint.Capabilities() 55 } 56 return minCapabilities 57 } 58 59 // MaxHeaderLength implements stack.LinkEndpoint. 60 func (m *InjectableEndpoint) MaxHeaderLength() uint16 { 61 minHeaderLen := ^uint16(0) 62 for _, endpoint := range m.routes { 63 if headerLen := endpoint.MaxHeaderLength(); headerLen < minHeaderLen { 64 minHeaderLen = headerLen 65 } 66 } 67 return minHeaderLen 68 } 69 70 // LinkAddress implements stack.LinkEndpoint. 71 func (m *InjectableEndpoint) LinkAddress() tcpip.LinkAddress { 72 return "" 73 } 74 75 // Attach implements stack.LinkEndpoint. 76 func (m *InjectableEndpoint) Attach(dispatcher stack.NetworkDispatcher) { 77 for _, endpoint := range m.routes { 78 endpoint.Attach(dispatcher) 79 } 80 m.mu.Lock() 81 m.dispatcher = dispatcher 82 m.mu.Unlock() 83 } 84 85 // IsAttached implements stack.LinkEndpoint. 86 func (m *InjectableEndpoint) IsAttached() bool { 87 m.mu.RLock() 88 defer m.mu.RUnlock() 89 return m.dispatcher != nil 90 } 91 92 // InjectInbound implements stack.InjectableLinkEndpoint. 93 func (m *InjectableEndpoint) InjectInbound(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 94 m.mu.RLock() 95 d := m.dispatcher 96 m.mu.RUnlock() 97 d.DeliverNetworkPacket(protocol, pkt) 98 } 99 100 // WritePackets writes outbound packets to the appropriate 101 // LinkInjectableEndpoint based on the RemoteAddress. HandleLocal only works if 102 // pkt.EgressRoute.RemoteAddress has a route registered in this endpoint. 103 func (m *InjectableEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) { 104 i := 0 105 for _, pkt := range pkts.AsSlice() { 106 endpoint, ok := m.routes[pkt.EgressRoute.RemoteAddress] 107 if !ok { 108 return i, &tcpip.ErrHostUnreachable{} 109 } 110 111 var tmpPkts stack.PacketBufferList 112 tmpPkts.PushBack(pkt) 113 114 n, err := endpoint.WritePackets(tmpPkts) 115 if err != nil { 116 return i, err 117 } 118 119 i += n 120 } 121 122 return i, nil 123 } 124 125 // InjectOutbound writes outbound packets to the appropriate 126 // LinkInjectableEndpoint based on the dest address. 127 func (m *InjectableEndpoint) InjectOutbound(dest tcpip.Address, packet *buffer.View) tcpip.Error { 128 endpoint, ok := m.routes[dest] 129 if !ok { 130 return &tcpip.ErrHostUnreachable{} 131 } 132 return endpoint.InjectOutbound(dest, packet) 133 } 134 135 // Wait implements stack.LinkEndpoint.Wait. 136 func (m *InjectableEndpoint) Wait() { 137 for _, ep := range m.routes { 138 ep.Wait() 139 } 140 } 141 142 // ARPHardwareType implements stack.LinkEndpoint.ARPHardwareType. 143 func (*InjectableEndpoint) ARPHardwareType() header.ARPHardwareType { 144 panic("unsupported operation") 145 } 146 147 // AddHeader implements stack.LinkEndpoint.AddHeader. 148 func (*InjectableEndpoint) AddHeader(*stack.PacketBuffer) {} 149 150 // ParseHeader implements stack.LinkEndpoint.ParseHeader. 151 func (*InjectableEndpoint) ParseHeader(*stack.PacketBuffer) bool { return true } 152 153 // NewInjectableEndpoint creates a new multi-endpoint injectable endpoint. 154 func NewInjectableEndpoint(routes map[tcpip.Address]stack.InjectableLinkEndpoint) *InjectableEndpoint { 155 return &InjectableEndpoint{ 156 routes: routes, 157 } 158 }