github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/tcpip/link/ethernet/ethernet.go (about) 1 // Copyright 2020 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 ethernet provides an implementation of an ethernet link endpoint that 16 // wraps an inner link endpoint. 17 package ethernet 18 19 import ( 20 "github.com/metacubex/gvisor/pkg/tcpip" 21 "github.com/metacubex/gvisor/pkg/tcpip/header" 22 "github.com/metacubex/gvisor/pkg/tcpip/link/nested" 23 "github.com/metacubex/gvisor/pkg/tcpip/stack" 24 ) 25 26 var _ stack.NetworkDispatcher = (*Endpoint)(nil) 27 var _ stack.LinkEndpoint = (*Endpoint)(nil) 28 29 // New returns an ethernet link endpoint that wraps an inner link endpoint. 30 func New(ep stack.LinkEndpoint) *Endpoint { 31 var e Endpoint 32 e.Endpoint.Init(ep, &e) 33 return &e 34 } 35 36 // Endpoint is an ethernet endpoint. 37 // 38 // It adds an ethernet header to packets before sending them out through its 39 // inner link endpoint and consumes an ethernet header before sending the 40 // packet to the stack. 41 type Endpoint struct { 42 nested.Endpoint 43 } 44 45 // LinkAddress implements stack.LinkEndpoint. 46 func (e *Endpoint) LinkAddress() tcpip.LinkAddress { 47 if l := e.Endpoint.LinkAddress(); len(l) != 0 { 48 return l 49 } 50 return header.UnspecifiedEthernetAddress 51 } 52 53 // MTU implements stack.LinkEndpoint. 54 func (e *Endpoint) MTU() uint32 { 55 if mtu := e.Endpoint.MTU(); mtu > header.EthernetMinimumSize { 56 return mtu - header.EthernetMinimumSize 57 } 58 return 0 59 } 60 61 // DeliverNetworkPacket implements stack.NetworkDispatcher. 62 func (e *Endpoint) DeliverNetworkPacket(_ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 63 if !e.ParseHeader(pkt) { 64 return 65 } 66 eth := header.Ethernet(pkt.LinkHeader().Slice()) 67 dst := eth.DestinationAddress() 68 if dst == header.EthernetBroadcastAddress { 69 pkt.PktType = tcpip.PacketBroadcast 70 } else if header.IsMulticastEthernetAddress(dst) { 71 pkt.PktType = tcpip.PacketMulticast 72 } else if dst == e.LinkAddress() { 73 pkt.PktType = tcpip.PacketHost 74 } else { 75 pkt.PktType = tcpip.PacketOtherHost 76 } 77 78 // Note, there is no need to check the destination link address here since 79 // the ethernet hardware filters frames based on their destination addresses. 80 e.Endpoint.DeliverNetworkPacket(eth.Type() /* protocol */, pkt) 81 } 82 83 // Capabilities implements stack.LinkEndpoint. 84 func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities { 85 c := e.Endpoint.Capabilities() 86 if c&stack.CapabilityLoopback == 0 { 87 c |= stack.CapabilityResolutionRequired 88 } 89 return c 90 } 91 92 // MaxHeaderLength implements stack.LinkEndpoint. 93 func (e *Endpoint) MaxHeaderLength() uint16 { 94 return header.EthernetMinimumSize + e.Endpoint.MaxHeaderLength() 95 } 96 97 // ARPHardwareType implements stack.LinkEndpoint. 98 func (e *Endpoint) ARPHardwareType() header.ARPHardwareType { 99 if a := e.Endpoint.ARPHardwareType(); a != header.ARPHardwareNone { 100 return a 101 } 102 return header.ARPHardwareEther 103 } 104 105 // AddHeader implements stack.LinkEndpoint. 106 func (*Endpoint) AddHeader(pkt *stack.PacketBuffer) { 107 eth := header.Ethernet(pkt.LinkHeader().Push(header.EthernetMinimumSize)) 108 fields := header.EthernetFields{ 109 SrcAddr: pkt.EgressRoute.LocalLinkAddress, 110 DstAddr: pkt.EgressRoute.RemoteLinkAddress, 111 Type: pkt.NetworkProtocolNumber, 112 } 113 eth.Encode(&fields) 114 } 115 116 // ParseHeader implements stack.LinkEndpoint. 117 func (*Endpoint) ParseHeader(pkt *stack.PacketBuffer) bool { 118 _, ok := pkt.LinkHeader().Consume(header.EthernetMinimumSize) 119 return ok 120 }