gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/link/ethernet/ethernet_test.go (about) 1 // Copyright 2021 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_test 16 17 import ( 18 "fmt" 19 "os" 20 "testing" 21 22 "github.com/google/go-cmp/cmp" 23 "gvisor.dev/gvisor/pkg/buffer" 24 "gvisor.dev/gvisor/pkg/refs" 25 "gvisor.dev/gvisor/pkg/tcpip" 26 "gvisor.dev/gvisor/pkg/tcpip/header" 27 "gvisor.dev/gvisor/pkg/tcpip/link/channel" 28 "gvisor.dev/gvisor/pkg/tcpip/link/ethernet" 29 "gvisor.dev/gvisor/pkg/tcpip/stack" 30 ) 31 32 var _ stack.NetworkDispatcher = (*testNetworkDispatcher)(nil) 33 34 type deliveredPacket struct { 35 protocol tcpip.NetworkProtocolNumber 36 packet *stack.PacketBuffer 37 } 38 39 type testNetworkDispatcher struct { 40 networkPackets []deliveredPacket 41 } 42 43 func (t *testNetworkDispatcher) DeliverNetworkPacket(proto tcpip.NetworkProtocolNumber, pb *stack.PacketBuffer) { 44 t.networkPackets = append(t.networkPackets, deliveredPacket{protocol: proto, packet: pb}) 45 } 46 47 func (*testNetworkDispatcher) DeliverLinkPacket(tcpip.NetworkProtocolNumber, *stack.PacketBuffer) { 48 panic("not implemented") 49 } 50 51 func TestDeliverNetworkPacket(t *testing.T) { 52 53 const ( 54 linkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06") 55 otherLinkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x07") 56 ) 57 58 for _, testCase := range []struct { 59 name string 60 dstAddr tcpip.LinkAddress 61 pktType tcpip.PacketType 62 }{ 63 { 64 name: "unicast", 65 dstAddr: linkAddr, 66 pktType: tcpip.PacketHost, 67 }, 68 { 69 name: "broadcast", 70 dstAddr: header.EthernetBroadcastAddress, 71 pktType: tcpip.PacketBroadcast, 72 }, 73 { 74 name: "multicast", 75 dstAddr: tcpip.LinkAddress("\xFF\x00\x00\x00\x05\x07"), 76 pktType: tcpip.PacketMulticast, 77 }, 78 { 79 name: "other host", 80 dstAddr: tcpip.LinkAddress("\x02\x02\x03\x04\x05\x08"), 81 pktType: tcpip.PacketOtherHost, 82 }, 83 } { 84 t.Run(testCase.name, func(t *testing.T) { 85 86 e := ethernet.New(channel.New(0, 0, linkAddr)) 87 var networkDispatcher testNetworkDispatcher 88 e.Attach(&networkDispatcher) 89 90 if got, want := len(networkDispatcher.networkPackets), 0; got != want { 91 t.Fatalf("got networkDispatcher.networkPackets = %d, want = %d", got, want) 92 } 93 94 const networkProtocol = header.IPv4ProtocolNumber 95 96 // An ethernet frame with a destination link address that is not assigned to 97 // our ethernet link endpoint should still be delivered to the network 98 // dispatcher since the ethernet endpoint is not expected to filter frames. 99 eth := make([]byte, header.EthernetMinimumSize) 100 header.Ethernet(eth).Encode(&header.EthernetFields{ 101 SrcAddr: otherLinkAddr, 102 DstAddr: testCase.dstAddr, 103 Type: networkProtocol, 104 }) 105 p := stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buffer.MakeWithData(eth)}) 106 defer p.DecRef() 107 e.DeliverNetworkPacket(0, p) 108 if got, want := len(networkDispatcher.networkPackets), 1; got != want { 109 t.Fatalf("got networkDispatcher.networkPackets = %d, want = %d", got, want) 110 } 111 delivered := networkDispatcher.networkPackets[0] 112 if diff := cmp.Diff(delivered.packet.LinkHeader().Slice(), eth); diff != "" { 113 t.Errorf("LinkHeader mismatch (-want +got):\n%s", diff) 114 } 115 if got, want := delivered.protocol, networkProtocol; got != want { 116 t.Errorf("got delivered.protocol = %d, want = %d", got, want) 117 } 118 if got, want := delivered.packet.PktType, testCase.pktType; got != want { 119 t.Errorf("got delivered.packet.PktType = %d, want = %d", got, want) 120 } 121 }) 122 } 123 } 124 125 type testLinkEndpoint struct { 126 stack.LinkEndpoint 127 128 mtu uint32 129 } 130 131 func (t *testLinkEndpoint) MTU() uint32 { 132 return t.mtu 133 } 134 135 func TestMTU(t *testing.T) { 136 const maxFrameSize = 1500 137 138 tests := []struct { 139 maxFrameSize uint32 140 expectedMTU uint32 141 }{ 142 { 143 maxFrameSize: 0, 144 expectedMTU: 0, 145 }, 146 { 147 maxFrameSize: header.EthernetMinimumSize - 1, 148 expectedMTU: 0, 149 }, 150 { 151 maxFrameSize: header.EthernetMinimumSize, 152 expectedMTU: 0, 153 }, 154 { 155 maxFrameSize: header.EthernetMinimumSize + 1, 156 expectedMTU: 1, 157 }, 158 { 159 maxFrameSize: maxFrameSize, 160 expectedMTU: maxFrameSize - header.EthernetMinimumSize, 161 }, 162 } 163 164 for _, test := range tests { 165 t.Run(fmt.Sprintf("MaxFrameSize=%d", test.maxFrameSize), func(t *testing.T) { 166 e := ethernet.New(&testLinkEndpoint{mtu: test.maxFrameSize}) 167 if got := e.MTU(); got != test.expectedMTU { 168 t.Errorf("got e.MTU() = %d, want = %d", got, test.expectedMTU) 169 } 170 }) 171 } 172 } 173 174 func TestWritePacketToRemoteAddHeader(t *testing.T) { 175 const ( 176 localLinkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06") 177 remoteLinkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x07") 178 179 netProto = 55 180 nicID = 1 181 ) 182 183 c := channel.New(1, header.EthernetMinimumSize, localLinkAddr) 184 185 s := stack.New(stack.Options{}) 186 if err := s.CreateNIC(nicID, ethernet.New(c)); err != nil { 187 t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) 188 } 189 190 if err := s.WritePacketToRemote(nicID, remoteLinkAddr, netProto, buffer.Buffer{}); err != nil { 191 t.Fatalf("s.WritePacketToRemote(%d, %s, _): %s", nicID, remoteLinkAddr, err) 192 } 193 194 { 195 pkt := c.Read() 196 if pkt == nil { 197 t.Fatal("expected to read a packet") 198 } 199 200 eth := header.Ethernet(pkt.LinkHeader().Slice()) 201 pkt.DecRef() 202 if got := eth.SourceAddress(); got != localLinkAddr { 203 t.Errorf("got eth.SourceAddress() = %s, want = %s", got, localLinkAddr) 204 } 205 if got := eth.DestinationAddress(); got != remoteLinkAddr { 206 t.Errorf("got eth.DestinationAddress() = %s, want = %s", got, remoteLinkAddr) 207 } 208 if got := eth.Type(); got != netProto { 209 t.Errorf("got eth.Type() = %d, want = %d", got, netProto) 210 } 211 } 212 } 213 214 func TestMain(m *testing.M) { 215 refs.SetLeakMode(refs.LeaksPanic) 216 code := m.Run() 217 refs.DoLeakCheck() 218 os.Exit(code) 219 }