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  }