summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/tests/integration
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/tests/integration')
-rw-r--r--pkg/tcpip/tests/integration/BUILD1
-rw-r--r--pkg/tcpip/tests/integration/forward_test.go471
-rw-r--r--pkg/tcpip/tests/integration/link_resolution_test.go279
-rw-r--r--pkg/tcpip/tests/integration/loopback_test.go4
-rw-r--r--pkg/tcpip/tests/integration/multicast_broadcast_test.go4
-rw-r--r--pkg/tcpip/tests/integration/route_test.go14
6 files changed, 507 insertions, 266 deletions
diff --git a/pkg/tcpip/tests/integration/BUILD b/pkg/tcpip/tests/integration/BUILD
index ca1e88e99..1742a178d 100644
--- a/pkg/tcpip/tests/integration/BUILD
+++ b/pkg/tcpip/tests/integration/BUILD
@@ -31,5 +31,6 @@ go_test(
"//pkg/tcpip/transport/udp",
"//pkg/waiter",
"@com_github_google_go_cmp//cmp:go_default_library",
+ "@com_github_google_go_cmp//cmp/cmpopts:go_default_library",
],
)
diff --git a/pkg/tcpip/tests/integration/forward_test.go b/pkg/tcpip/tests/integration/forward_test.go
index 4c2084d19..49acd504e 100644
--- a/pkg/tcpip/tests/integration/forward_test.go
+++ b/pkg/tcpip/tests/integration/forward_test.go
@@ -30,6 +30,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
+ "gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -157,13 +158,13 @@ func TestForwarding(t *testing.T) {
tests := []struct {
name string
- epAndAddrs func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack) endpointAndAddresses
+ epAndAddrs func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack, proto tcpip.TransportProtocolNumber) endpointAndAddresses
}{
{
name: "IPv4 host1 server with host2 client",
- epAndAddrs: func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack) endpointAndAddresses {
- ep1, ep1WECH := newEP(t, host1Stack, udp.ProtocolNumber, ipv4.ProtocolNumber)
- ep2, ep2WECH := newEP(t, host2Stack, udp.ProtocolNumber, ipv4.ProtocolNumber)
+ epAndAddrs: func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack, proto tcpip.TransportProtocolNumber) endpointAndAddresses {
+ ep1, ep1WECH := newEP(t, host1Stack, proto, ipv4.ProtocolNumber)
+ ep2, ep2WECH := newEP(t, host2Stack, proto, ipv4.ProtocolNumber)
return endpointAndAddresses{
serverEP: ep1,
serverAddr: host1IPv4Addr.AddressWithPrefix.Address,
@@ -177,9 +178,9 @@ func TestForwarding(t *testing.T) {
},
{
name: "IPv6 host2 server with host1 client",
- epAndAddrs: func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack) endpointAndAddresses {
- ep1, ep1WECH := newEP(t, host2Stack, udp.ProtocolNumber, ipv6.ProtocolNumber)
- ep2, ep2WECH := newEP(t, host1Stack, udp.ProtocolNumber, ipv6.ProtocolNumber)
+ epAndAddrs: func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack, proto tcpip.TransportProtocolNumber) endpointAndAddresses {
+ ep1, ep1WECH := newEP(t, host2Stack, proto, ipv6.ProtocolNumber)
+ ep2, ep2WECH := newEP(t, host1Stack, proto, ipv6.ProtocolNumber)
return endpointAndAddresses{
serverEP: ep1,
serverAddr: host2IPv6Addr.AddressWithPrefix.Address,
@@ -193,9 +194,9 @@ func TestForwarding(t *testing.T) {
},
{
name: "IPv4 host2 server with routerNIC1 client",
- epAndAddrs: func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack) endpointAndAddresses {
- ep1, ep1WECH := newEP(t, host2Stack, udp.ProtocolNumber, ipv4.ProtocolNumber)
- ep2, ep2WECH := newEP(t, routerStack, udp.ProtocolNumber, ipv4.ProtocolNumber)
+ epAndAddrs: func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack, proto tcpip.TransportProtocolNumber) endpointAndAddresses {
+ ep1, ep1WECH := newEP(t, host2Stack, proto, ipv4.ProtocolNumber)
+ ep2, ep2WECH := newEP(t, routerStack, proto, ipv4.ProtocolNumber)
return endpointAndAddresses{
serverEP: ep1,
serverAddr: host2IPv4Addr.AddressWithPrefix.Address,
@@ -209,9 +210,9 @@ func TestForwarding(t *testing.T) {
},
{
name: "IPv6 routerNIC2 server with host1 client",
- epAndAddrs: func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack) endpointAndAddresses {
- ep1, ep1WECH := newEP(t, routerStack, udp.ProtocolNumber, ipv6.ProtocolNumber)
- ep2, ep2WECH := newEP(t, host1Stack, udp.ProtocolNumber, ipv6.ProtocolNumber)
+ epAndAddrs: func(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack, proto tcpip.TransportProtocolNumber) endpointAndAddresses {
+ ep1, ep1WECH := newEP(t, routerStack, proto, ipv6.ProtocolNumber)
+ ep2, ep2WECH := newEP(t, host1Stack, proto, ipv6.ProtocolNumber)
return endpointAndAddresses{
serverEP: ep1,
serverAddr: routerNIC2IPv6Addr.AddressWithPrefix.Address,
@@ -225,202 +226,270 @@ func TestForwarding(t *testing.T) {
},
}
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- stackOpts := stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
- TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
- }
-
- host1Stack := stack.New(stackOpts)
- routerStack := stack.New(stackOpts)
- host2Stack := stack.New(stackOpts)
-
- host1NIC, routerNIC1 := pipe.New(linkAddr1, linkAddr2)
- routerNIC2, host2NIC := pipe.New(linkAddr3, linkAddr4)
-
- if err := host1Stack.CreateNIC(host1NICID, newEthernetEndpoint(host1NIC)); err != nil {
- t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err)
- }
- if err := routerStack.CreateNIC(routerNICID1, newEthernetEndpoint(routerNIC1)); err != nil {
- t.Fatalf("routerStack.CreateNIC(%d, _): %s", routerNICID1, err)
- }
- if err := routerStack.CreateNIC(routerNICID2, newEthernetEndpoint(routerNIC2)); err != nil {
- t.Fatalf("routerStack.CreateNIC(%d, _): %s", routerNICID2, err)
- }
- if err := host2Stack.CreateNIC(host2NICID, newEthernetEndpoint(host2NIC)); err != nil {
- t.Fatalf("host2Stack.CreateNIC(%d, _): %s", host2NICID, err)
- }
-
- if err := routerStack.SetForwarding(ipv4.ProtocolNumber, true); err != nil {
- t.Fatalf("routerStack.SetForwarding(%d): %s", ipv4.ProtocolNumber, err)
- }
- if err := routerStack.SetForwarding(ipv6.ProtocolNumber, true); err != nil {
- t.Fatalf("routerStack.SetForwarding(%d): %s", ipv6.ProtocolNumber, err)
- }
-
- if err := host1Stack.AddProtocolAddress(host1NICID, host1IPv4Addr); err != nil {
- t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, host1IPv4Addr, err)
- }
- if err := routerStack.AddProtocolAddress(routerNICID1, routerNIC1IPv4Addr); err != nil {
- t.Fatalf("routerStack.AddProtocolAddress(%d, %#v): %s", routerNICID1, routerNIC1IPv4Addr, err)
- }
- if err := routerStack.AddProtocolAddress(routerNICID2, routerNIC2IPv4Addr); err != nil {
- t.Fatalf("routerStack.AddProtocolAddress(%d, %#v): %s", routerNICID2, routerNIC2IPv4Addr, err)
- }
- if err := host2Stack.AddProtocolAddress(host2NICID, host2IPv4Addr); err != nil {
- t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, host2IPv4Addr, err)
- }
- if err := host1Stack.AddProtocolAddress(host1NICID, host1IPv6Addr); err != nil {
- t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, host1IPv6Addr, err)
- }
- if err := routerStack.AddProtocolAddress(routerNICID1, routerNIC1IPv6Addr); err != nil {
- t.Fatalf("routerStack.AddProtocolAddress(%d, %#v): %s", routerNICID1, routerNIC1IPv6Addr, err)
- }
- if err := routerStack.AddProtocolAddress(routerNICID2, routerNIC2IPv6Addr); err != nil {
- t.Fatalf("routerStack.AddProtocolAddress(%d, %#v): %s", routerNICID2, routerNIC2IPv6Addr, err)
- }
- if err := host2Stack.AddProtocolAddress(host2NICID, host2IPv6Addr); err != nil {
- t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, host2IPv6Addr, err)
- }
-
- host1Stack.SetRouteTable([]tcpip.Route{
- {
- Destination: host1IPv4Addr.AddressWithPrefix.Subnet(),
- NIC: host1NICID,
- },
- {
- Destination: host1IPv6Addr.AddressWithPrefix.Subnet(),
- NIC: host1NICID,
- },
- {
- Destination: host2IPv4Addr.AddressWithPrefix.Subnet(),
- Gateway: routerNIC1IPv4Addr.AddressWithPrefix.Address,
- NIC: host1NICID,
- },
- {
- Destination: host2IPv6Addr.AddressWithPrefix.Subnet(),
- Gateway: routerNIC1IPv6Addr.AddressWithPrefix.Address,
- NIC: host1NICID,
- },
- })
- routerStack.SetRouteTable([]tcpip.Route{
- {
- Destination: routerNIC1IPv4Addr.AddressWithPrefix.Subnet(),
- NIC: routerNICID1,
- },
- {
- Destination: routerNIC1IPv6Addr.AddressWithPrefix.Subnet(),
- NIC: routerNICID1,
- },
- {
- Destination: routerNIC2IPv4Addr.AddressWithPrefix.Subnet(),
- NIC: routerNICID2,
- },
- {
- Destination: routerNIC2IPv6Addr.AddressWithPrefix.Subnet(),
- NIC: routerNICID2,
- },
- })
- host2Stack.SetRouteTable([]tcpip.Route{
- {
- Destination: host2IPv4Addr.AddressWithPrefix.Subnet(),
- NIC: host2NICID,
- },
- {
- Destination: host2IPv6Addr.AddressWithPrefix.Subnet(),
- NIC: host2NICID,
- },
- {
- Destination: host1IPv4Addr.AddressWithPrefix.Subnet(),
- Gateway: routerNIC2IPv4Addr.AddressWithPrefix.Address,
- NIC: host2NICID,
- },
- {
- Destination: host1IPv6Addr.AddressWithPrefix.Subnet(),
- Gateway: routerNIC2IPv6Addr.AddressWithPrefix.Address,
- NIC: host2NICID,
- },
- })
-
- epsAndAddrs := test.epAndAddrs(t, host1Stack, routerStack, host2Stack)
- defer epsAndAddrs.serverEP.Close()
- defer epsAndAddrs.clientEP.Close()
-
- serverAddr := tcpip.FullAddress{Addr: epsAndAddrs.serverAddr, Port: listenPort}
- if err := epsAndAddrs.serverEP.Bind(serverAddr); err != nil {
- t.Fatalf("epsAndAddrs.serverEP.Bind(%#v): %s", serverAddr, err)
- }
- clientAddr := tcpip.FullAddress{Addr: epsAndAddrs.clientAddr}
- if err := epsAndAddrs.clientEP.Bind(clientAddr); err != nil {
- t.Fatalf("epsAndAddrs.clientEP.Bind(%#v): %s", clientAddr, err)
- }
-
- write := func(ep tcpip.Endpoint, data []byte, to *tcpip.FullAddress) {
+ subTests := []struct {
+ name string
+ proto tcpip.TransportProtocolNumber
+ expectedConnectErr *tcpip.Error
+ setupServerSide func(t *testing.T, ep tcpip.Endpoint, ch <-chan struct{}, clientAddr tcpip.FullAddress) (tcpip.Endpoint, chan struct{})
+ needRemoteAddr bool
+ }{
+ {
+ name: "UDP",
+ proto: udp.ProtocolNumber,
+ expectedConnectErr: nil,
+ setupServerSide: func(t *testing.T, ep tcpip.Endpoint, _ <-chan struct{}, clientAddr tcpip.FullAddress) (tcpip.Endpoint, chan struct{}) {
t.Helper()
- dataPayload := tcpip.SlicePayload(data)
- wOpts := tcpip.WriteOptions{To: to}
- n, ch, err := ep.Write(dataPayload, wOpts)
- if err == tcpip.ErrNoLinkAddress {
- // Wait for link resolution to complete.
- <-ch
- n, _, err = ep.Write(dataPayload, wOpts)
- }
- if err != nil {
- t.Fatalf("ep.Write(_, _): %s", err)
- }
- if want := int64(len(data)); n != want {
- t.Fatalf("got ep.Write(_, _) = (%d, _, _), want = (%d, _, _)", n, want)
+ if err := ep.Connect(clientAddr); err != nil {
+ t.Fatalf("ep.Connect(%#v): %s", clientAddr, err)
}
- }
-
- data := []byte{1, 2, 3, 4}
- write(epsAndAddrs.clientEP, data, &serverAddr)
-
- read := func(ch chan struct{}, ep tcpip.Endpoint, data []byte, expectedFrom tcpip.Address) tcpip.FullAddress {
+ return nil, nil
+ },
+ needRemoteAddr: true,
+ },
+ {
+ name: "TCP",
+ proto: tcp.ProtocolNumber,
+ expectedConnectErr: tcpip.ErrConnectStarted,
+ setupServerSide: func(t *testing.T, ep tcpip.Endpoint, ch <-chan struct{}, clientAddr tcpip.FullAddress) (tcpip.Endpoint, chan struct{}) {
t.Helper()
- // Wait for the endpoint to be readable.
- <-ch
- var buf bytes.Buffer
- opts := tcpip.ReadOptions{NeedRemoteAddr: true}
- res, err := ep.Read(&buf, len(data), opts)
- if err != nil {
- t.Fatalf("ep.Read(_, %d, %#v): %s", len(data), opts, err)
+ if err := ep.Listen(1); err != nil {
+ t.Fatalf("ep.Listen(1): %s", err)
}
-
- if diff := cmp.Diff(tcpip.ReadResult{
- Count: len(data),
- Total: len(data),
- RemoteAddr: tcpip.FullAddress{Addr: expectedFrom},
- }, res, checker.IgnoreCmpPath(
- "ControlMessages",
- "RemoteAddr.NIC",
- "RemoteAddr.Port",
- )); diff != "" {
- t.Errorf("ep.Read: unexpected result (-want +got):\n%s", diff)
- }
- if diff := cmp.Diff(buf.Bytes(), data); diff != "" {
- t.Errorf("received data mismatch (-want +got):\n%s", diff)
- }
-
- if t.Failed() {
- t.FailNow()
+ var addr tcpip.FullAddress
+ for {
+ newEP, wq, err := ep.Accept(&addr)
+ if err == tcpip.ErrWouldBlock {
+ <-ch
+ continue
+ }
+ if err != nil {
+ t.Fatalf("ep.Accept(_): %s", err)
+ }
+ if diff := cmp.Diff(clientAddr, addr, checker.IgnoreCmpPath(
+ "NIC",
+ )); diff != "" {
+ t.Errorf("accepted address mismatch (-want +got):\n%s", diff)
+ }
+
+ we, newCH := waiter.NewChannelEntry(nil)
+ wq.EventRegister(&we, waiter.EventIn)
+ return newEP, newCH
}
+ },
+ needRemoteAddr: false,
+ },
+ }
- return res.RemoteAddr
- }
-
- addr := read(epsAndAddrs.serverReadableCH, epsAndAddrs.serverEP, data, epsAndAddrs.clientAddr)
- // Unspecify the NIC since NIC IDs are meaningless across stacks.
- addr.NIC = 0
-
- data = tcpip.SlicePayload([]byte{5, 6, 7, 8, 9, 10, 11, 12})
- write(epsAndAddrs.serverEP, data, &addr)
- addr = read(epsAndAddrs.clientReadableCH, epsAndAddrs.clientEP, data, epsAndAddrs.serverAddr)
- if addr.Port != listenPort {
- t.Errorf("got addr.Port = %d, want = %d", addr.Port, listenPort)
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ for _, subTest := range subTests {
+ t.Run(subTest.name, func(t *testing.T) {
+ stackOpts := stack.Options{
+ NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
+ TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol, tcp.NewProtocol},
+ }
+
+ host1Stack := stack.New(stackOpts)
+ routerStack := stack.New(stackOpts)
+ host2Stack := stack.New(stackOpts)
+
+ host1NIC, routerNIC1 := pipe.New(linkAddr1, linkAddr2)
+ routerNIC2, host2NIC := pipe.New(linkAddr3, linkAddr4)
+
+ if err := host1Stack.CreateNIC(host1NICID, newEthernetEndpoint(host1NIC)); err != nil {
+ t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err)
+ }
+ if err := routerStack.CreateNIC(routerNICID1, newEthernetEndpoint(routerNIC1)); err != nil {
+ t.Fatalf("routerStack.CreateNIC(%d, _): %s", routerNICID1, err)
+ }
+ if err := routerStack.CreateNIC(routerNICID2, newEthernetEndpoint(routerNIC2)); err != nil {
+ t.Fatalf("routerStack.CreateNIC(%d, _): %s", routerNICID2, err)
+ }
+ if err := host2Stack.CreateNIC(host2NICID, newEthernetEndpoint(host2NIC)); err != nil {
+ t.Fatalf("host2Stack.CreateNIC(%d, _): %s", host2NICID, err)
+ }
+
+ if err := routerStack.SetForwarding(ipv4.ProtocolNumber, true); err != nil {
+ t.Fatalf("routerStack.SetForwarding(%d): %s", ipv4.ProtocolNumber, err)
+ }
+ if err := routerStack.SetForwarding(ipv6.ProtocolNumber, true); err != nil {
+ t.Fatalf("routerStack.SetForwarding(%d): %s", ipv6.ProtocolNumber, err)
+ }
+
+ if err := host1Stack.AddProtocolAddress(host1NICID, host1IPv4Addr); err != nil {
+ t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, host1IPv4Addr, err)
+ }
+ if err := routerStack.AddProtocolAddress(routerNICID1, routerNIC1IPv4Addr); err != nil {
+ t.Fatalf("routerStack.AddProtocolAddress(%d, %#v): %s", routerNICID1, routerNIC1IPv4Addr, err)
+ }
+ if err := routerStack.AddProtocolAddress(routerNICID2, routerNIC2IPv4Addr); err != nil {
+ t.Fatalf("routerStack.AddProtocolAddress(%d, %#v): %s", routerNICID2, routerNIC2IPv4Addr, err)
+ }
+ if err := host2Stack.AddProtocolAddress(host2NICID, host2IPv4Addr); err != nil {
+ t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, host2IPv4Addr, err)
+ }
+ if err := host1Stack.AddProtocolAddress(host1NICID, host1IPv6Addr); err != nil {
+ t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, host1IPv6Addr, err)
+ }
+ if err := routerStack.AddProtocolAddress(routerNICID1, routerNIC1IPv6Addr); err != nil {
+ t.Fatalf("routerStack.AddProtocolAddress(%d, %#v): %s", routerNICID1, routerNIC1IPv6Addr, err)
+ }
+ if err := routerStack.AddProtocolAddress(routerNICID2, routerNIC2IPv6Addr); err != nil {
+ t.Fatalf("routerStack.AddProtocolAddress(%d, %#v): %s", routerNICID2, routerNIC2IPv6Addr, err)
+ }
+ if err := host2Stack.AddProtocolAddress(host2NICID, host2IPv6Addr); err != nil {
+ t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, host2IPv6Addr, err)
+ }
+
+ host1Stack.SetRouteTable([]tcpip.Route{
+ {
+ Destination: host1IPv4Addr.AddressWithPrefix.Subnet(),
+ NIC: host1NICID,
+ },
+ {
+ Destination: host1IPv6Addr.AddressWithPrefix.Subnet(),
+ NIC: host1NICID,
+ },
+ {
+ Destination: host2IPv4Addr.AddressWithPrefix.Subnet(),
+ Gateway: routerNIC1IPv4Addr.AddressWithPrefix.Address,
+ NIC: host1NICID,
+ },
+ {
+ Destination: host2IPv6Addr.AddressWithPrefix.Subnet(),
+ Gateway: routerNIC1IPv6Addr.AddressWithPrefix.Address,
+ NIC: host1NICID,
+ },
+ })
+ routerStack.SetRouteTable([]tcpip.Route{
+ {
+ Destination: routerNIC1IPv4Addr.AddressWithPrefix.Subnet(),
+ NIC: routerNICID1,
+ },
+ {
+ Destination: routerNIC1IPv6Addr.AddressWithPrefix.Subnet(),
+ NIC: routerNICID1,
+ },
+ {
+ Destination: routerNIC2IPv4Addr.AddressWithPrefix.Subnet(),
+ NIC: routerNICID2,
+ },
+ {
+ Destination: routerNIC2IPv6Addr.AddressWithPrefix.Subnet(),
+ NIC: routerNICID2,
+ },
+ })
+ host2Stack.SetRouteTable([]tcpip.Route{
+ {
+ Destination: host2IPv4Addr.AddressWithPrefix.Subnet(),
+ NIC: host2NICID,
+ },
+ {
+ Destination: host2IPv6Addr.AddressWithPrefix.Subnet(),
+ NIC: host2NICID,
+ },
+ {
+ Destination: host1IPv4Addr.AddressWithPrefix.Subnet(),
+ Gateway: routerNIC2IPv4Addr.AddressWithPrefix.Address,
+ NIC: host2NICID,
+ },
+ {
+ Destination: host1IPv6Addr.AddressWithPrefix.Subnet(),
+ Gateway: routerNIC2IPv6Addr.AddressWithPrefix.Address,
+ NIC: host2NICID,
+ },
+ })
+
+ epsAndAddrs := test.epAndAddrs(t, host1Stack, routerStack, host2Stack, subTest.proto)
+ defer epsAndAddrs.serverEP.Close()
+ defer epsAndAddrs.clientEP.Close()
+
+ serverAddr := tcpip.FullAddress{Addr: epsAndAddrs.serverAddr, Port: listenPort}
+ if err := epsAndAddrs.serverEP.Bind(serverAddr); err != nil {
+ t.Fatalf("epsAndAddrs.serverEP.Bind(%#v): %s", serverAddr, err)
+ }
+ clientAddr := tcpip.FullAddress{Addr: epsAndAddrs.clientAddr}
+ if err := epsAndAddrs.clientEP.Bind(clientAddr); err != nil {
+ t.Fatalf("epsAndAddrs.clientEP.Bind(%#v): %s", clientAddr, err)
+ }
+
+ if err := epsAndAddrs.clientEP.Connect(serverAddr); err != subTest.expectedConnectErr {
+ t.Fatalf("got epsAndAddrs.clientEP.Connect(%#v) = %s, want = %s", serverAddr, err, subTest.expectedConnectErr)
+ }
+ if addr, err := epsAndAddrs.clientEP.GetLocalAddress(); err != nil {
+ t.Fatalf("epsAndAddrs.clientEP.GetLocalAddress(): %s", err)
+ } else {
+ clientAddr = addr
+ clientAddr.NIC = 0
+ }
+
+ serverEP := epsAndAddrs.serverEP
+ serverCH := epsAndAddrs.serverReadableCH
+ if ep, ch := subTest.setupServerSide(t, serverEP, serverCH, clientAddr); ep != nil {
+ defer ep.Close()
+ serverEP = ep
+ serverCH = ch
+ }
+
+ write := func(ep tcpip.Endpoint, data []byte) {
+ t.Helper()
+
+ dataPayload := tcpip.SlicePayload(data)
+ var wOpts tcpip.WriteOptions
+ n, err := ep.Write(dataPayload, wOpts)
+ if err != nil {
+ t.Fatalf("ep.Write(_, %#v): %s", wOpts, err)
+ }
+ if want := int64(len(data)); n != want {
+ t.Fatalf("got ep.Write(_, %#v) = (%d, _), want = (%d, _)", wOpts, n, want)
+ }
+ }
+
+ data := []byte{1, 2, 3, 4}
+ write(epsAndAddrs.clientEP, data)
+
+ read := func(ch chan struct{}, ep tcpip.Endpoint, data []byte, expectedFrom tcpip.FullAddress) {
+ t.Helper()
+
+ // Wait for the endpoint to be readable.
+ <-ch
+ var buf bytes.Buffer
+ opts := tcpip.ReadOptions{NeedRemoteAddr: subTest.needRemoteAddr}
+ res, err := ep.Read(&buf, len(data), opts)
+ if err != nil {
+ t.Fatalf("ep.Read(_, %d, %#v): %s", len(data), opts, err)
+ }
+
+ readResult := tcpip.ReadResult{
+ Count: len(data),
+ Total: len(data),
+ }
+ if subTest.needRemoteAddr {
+ readResult.RemoteAddr = expectedFrom
+ }
+ if diff := cmp.Diff(readResult, res, checker.IgnoreCmpPath(
+ "ControlMessages",
+ "RemoteAddr.NIC",
+ )); diff != "" {
+ t.Errorf("ep.Read: unexpected result (-want +got):\n%s", diff)
+ }
+ if diff := cmp.Diff(buf.Bytes(), data); diff != "" {
+ t.Errorf("received data mismatch (-want +got):\n%s", diff)
+ }
+
+ if t.Failed() {
+ t.FailNow()
+ }
+ }
+
+ read(serverCH, serverEP, data, clientAddr)
+
+ data = tcpip.SlicePayload([]byte{5, 6, 7, 8, 9, 10, 11, 12})
+ write(serverEP, data)
+ read(epsAndAddrs.clientReadableCH, epsAndAddrs.clientEP, data, serverAddr)
+ })
}
})
}
diff --git a/pkg/tcpip/tests/integration/link_resolution_test.go b/pkg/tcpip/tests/integration/link_resolution_test.go
index b4bffaec1..ed00c90d4 100644
--- a/pkg/tcpip/tests/integration/link_resolution_test.go
+++ b/pkg/tcpip/tests/integration/link_resolution_test.go
@@ -20,6 +20,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checker"
"gvisor.dev/gvisor/pkg/tcpip/header"
@@ -29,6 +30,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
+ "gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -54,6 +56,13 @@ var (
PrefixLen: 8,
},
}
+ ipv4Addr3 = tcpip.ProtocolAddress{
+ Protocol: ipv4.ProtocolNumber,
+ AddressWithPrefix: tcpip.AddressWithPrefix{
+ Address: tcpip.Address(net.ParseIP("192.168.0.3").To4()),
+ PrefixLen: 8,
+ },
+ }
ipv6Addr1 = tcpip.ProtocolAddress{
Protocol: ipv6.ProtocolNumber,
AddressWithPrefix: tcpip.AddressWithPrefix{
@@ -68,8 +77,65 @@ var (
PrefixLen: 64,
},
}
+ ipv6Addr3 = tcpip.ProtocolAddress{
+ Protocol: ipv6.ProtocolNumber,
+ AddressWithPrefix: tcpip.AddressWithPrefix{
+ Address: tcpip.Address(net.ParseIP("a::3").To16()),
+ PrefixLen: 64,
+ },
+ }
)
+func setupStack(t *testing.T, stackOpts stack.Options, host1NICID, host2NICID tcpip.NICID) (*stack.Stack, *stack.Stack) {
+ host1Stack := stack.New(stackOpts)
+ host2Stack := stack.New(stackOpts)
+
+ host1NIC, host2NIC := pipe.New(linkAddr1, linkAddr2)
+
+ if err := host1Stack.CreateNIC(host1NICID, newEthernetEndpoint(host1NIC)); err != nil {
+ t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err)
+ }
+ if err := host2Stack.CreateNIC(host2NICID, newEthernetEndpoint(host2NIC)); err != nil {
+ t.Fatalf("host2Stack.CreateNIC(%d, _): %s", host2NICID, err)
+ }
+
+ if err := host1Stack.AddProtocolAddress(host1NICID, ipv4Addr1); err != nil {
+ t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, ipv4Addr1, err)
+ }
+ if err := host2Stack.AddProtocolAddress(host2NICID, ipv4Addr2); err != nil {
+ t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, ipv4Addr2, err)
+ }
+ if err := host1Stack.AddProtocolAddress(host1NICID, ipv6Addr1); err != nil {
+ t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, ipv6Addr1, err)
+ }
+ if err := host2Stack.AddProtocolAddress(host2NICID, ipv6Addr2); err != nil {
+ t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, ipv6Addr2, err)
+ }
+
+ host1Stack.SetRouteTable([]tcpip.Route{
+ {
+ Destination: ipv4Addr1.AddressWithPrefix.Subnet(),
+ NIC: host1NICID,
+ },
+ {
+ Destination: ipv6Addr1.AddressWithPrefix.Subnet(),
+ NIC: host1NICID,
+ },
+ })
+ host2Stack.SetRouteTable([]tcpip.Route{
+ {
+ Destination: ipv4Addr2.AddressWithPrefix.Subnet(),
+ NIC: host2NICID,
+ },
+ {
+ Destination: ipv6Addr2.AddressWithPrefix.Subnet(),
+ NIC: host2NICID,
+ },
+ })
+
+ return host1Stack, host2Stack
+}
+
// TestPing tests that two hosts can ping eachother when link resolution is
// enabled.
func TestPing(t *testing.T) {
@@ -128,51 +194,7 @@ func TestPing(t *testing.T) {
TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol4, icmp.NewProtocol6},
}
- host1Stack := stack.New(stackOpts)
- host2Stack := stack.New(stackOpts)
-
- host1NIC, host2NIC := pipe.New(linkAddr1, linkAddr2)
-
- if err := host1Stack.CreateNIC(host1NICID, newEthernetEndpoint(host1NIC)); err != nil {
- t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err)
- }
- if err := host2Stack.CreateNIC(host2NICID, newEthernetEndpoint(host2NIC)); err != nil {
- t.Fatalf("host2Stack.CreateNIC(%d, _): %s", host2NICID, err)
- }
-
- if err := host1Stack.AddProtocolAddress(host1NICID, ipv4Addr1); err != nil {
- t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, ipv4Addr1, err)
- }
- if err := host2Stack.AddProtocolAddress(host2NICID, ipv4Addr2); err != nil {
- t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, ipv4Addr2, err)
- }
- if err := host1Stack.AddProtocolAddress(host1NICID, ipv6Addr1); err != nil {
- t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, ipv6Addr1, err)
- }
- if err := host2Stack.AddProtocolAddress(host2NICID, ipv6Addr2); err != nil {
- t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, ipv6Addr2, err)
- }
-
- host1Stack.SetRouteTable([]tcpip.Route{
- {
- Destination: ipv4Addr1.AddressWithPrefix.Subnet(),
- NIC: host1NICID,
- },
- {
- Destination: ipv6Addr1.AddressWithPrefix.Subnet(),
- NIC: host1NICID,
- },
- })
- host2Stack.SetRouteTable([]tcpip.Route{
- {
- Destination: ipv4Addr2.AddressWithPrefix.Subnet(),
- NIC: host2NICID,
- },
- {
- Destination: ipv6Addr2.AddressWithPrefix.Subnet(),
- NIC: host2NICID,
- },
- })
+ host1Stack, _ := setupStack(t, stackOpts, host1NICID, host2NICID)
var wq waiter.Queue
we, waiterCH := waiter.NewChannelEntry(nil)
@@ -183,19 +205,12 @@ func TestPing(t *testing.T) {
}
defer ep.Close()
- // The first write should trigger link resolution.
icmpBuf := test.icmpBuf(t)
wOpts := tcpip.WriteOptions{To: &tcpip.FullAddress{Addr: test.remoteAddr}}
- if _, ch, err := ep.Write(tcpip.SlicePayload(icmpBuf), wOpts); err != tcpip.ErrNoLinkAddress {
- t.Fatalf("got ep.Write(_, _) = %s, want = %s", err, tcpip.ErrNoLinkAddress)
- } else {
- // Wait for link resolution to complete.
- <-ch
- }
- if n, _, err := ep.Write(tcpip.SlicePayload(icmpBuf), wOpts); err != nil {
+ if n, err := ep.Write(tcpip.SlicePayload(icmpBuf), wOpts); err != nil {
t.Fatalf("ep.Write(_, _): %s", err)
} else if want := int64(len(icmpBuf)); n != want {
- t.Fatalf("got ep.Write(_, _) = (%d, _, _), want = (%d, _, _)", n, want)
+ t.Fatalf("got ep.Write(_, _) = (%d, _), want = (%d, _)", n, want)
}
// Wait for the endpoint to be readable.
@@ -224,3 +239,159 @@ func TestPing(t *testing.T) {
})
}
}
+
+func TestTCPLinkResolutionFailure(t *testing.T) {
+ const (
+ host1NICID = 1
+ host2NICID = 4
+ )
+
+ tests := []struct {
+ name string
+ netProto tcpip.NetworkProtocolNumber
+ remoteAddr tcpip.Address
+ expectedWriteErr *tcpip.Error
+ sockError tcpip.SockError
+ }{
+ {
+ name: "IPv4 with resolvable remote",
+ netProto: ipv4.ProtocolNumber,
+ remoteAddr: ipv4Addr2.AddressWithPrefix.Address,
+ expectedWriteErr: nil,
+ },
+ {
+ name: "IPv6 with resolvable remote",
+ netProto: ipv6.ProtocolNumber,
+ remoteAddr: ipv6Addr2.AddressWithPrefix.Address,
+ expectedWriteErr: nil,
+ },
+ {
+ name: "IPv4 without resolvable remote",
+ netProto: ipv4.ProtocolNumber,
+ remoteAddr: ipv4Addr3.AddressWithPrefix.Address,
+ expectedWriteErr: tcpip.ErrNoRoute,
+ sockError: tcpip.SockError{
+ Err: tcpip.ErrNoRoute,
+ ErrType: byte(header.ICMPv4DstUnreachable),
+ ErrCode: byte(header.ICMPv4HostUnreachable),
+ ErrOrigin: tcpip.SockExtErrorOriginICMP,
+ Dst: tcpip.FullAddress{
+ NIC: host1NICID,
+ Addr: ipv4Addr3.AddressWithPrefix.Address,
+ Port: 1234,
+ },
+ Offender: tcpip.FullAddress{
+ NIC: host1NICID,
+ Addr: ipv4Addr1.AddressWithPrefix.Address,
+ },
+ NetProto: ipv4.ProtocolNumber,
+ },
+ },
+ {
+ name: "IPv6 without resolvable remote",
+ netProto: ipv6.ProtocolNumber,
+ remoteAddr: ipv6Addr3.AddressWithPrefix.Address,
+ expectedWriteErr: tcpip.ErrNoRoute,
+ sockError: tcpip.SockError{
+ Err: tcpip.ErrNoRoute,
+ ErrType: byte(header.ICMPv6DstUnreachable),
+ ErrCode: byte(header.ICMPv6AddressUnreachable),
+ ErrOrigin: tcpip.SockExtErrorOriginICMP6,
+ Dst: tcpip.FullAddress{
+ NIC: host1NICID,
+ Addr: ipv6Addr3.AddressWithPrefix.Address,
+ Port: 1234,
+ },
+ Offender: tcpip.FullAddress{
+ NIC: host1NICID,
+ Addr: ipv6Addr1.AddressWithPrefix.Address,
+ },
+ NetProto: ipv6.ProtocolNumber,
+ },
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ stackOpts := stack.Options{
+ NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
+ TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
+ }
+
+ host1Stack, host2Stack := setupStack(t, stackOpts, host1NICID, host2NICID)
+
+ var listenerWQ waiter.Queue
+ listenerEP, err := host2Stack.NewEndpoint(tcp.ProtocolNumber, test.netProto, &listenerWQ)
+ if err != nil {
+ t.Fatalf("host2Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, test.netProto, err)
+ }
+ defer listenerEP.Close()
+
+ listenerAddr := tcpip.FullAddress{Port: 1234}
+ if err := listenerEP.Bind(listenerAddr); err != nil {
+ t.Fatalf("listenerEP.Bind(%#v): %s", listenerAddr, err)
+ }
+
+ if err := listenerEP.Listen(1); err != nil {
+ t.Fatalf("listenerEP.Listen(1): %s", err)
+ }
+
+ var clientWQ waiter.Queue
+ we, ch := waiter.NewChannelEntry(nil)
+ clientWQ.EventRegister(&we, waiter.EventOut|waiter.EventErr)
+ clientEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, test.netProto, &clientWQ)
+ if err != nil {
+ t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, test.netProto, err)
+ }
+ defer clientEP.Close()
+
+ sockOpts := clientEP.SocketOptions()
+ sockOpts.SetRecvError(true)
+
+ remoteAddr := listenerAddr
+ remoteAddr.Addr = test.remoteAddr
+ if err := clientEP.Connect(remoteAddr); err != tcpip.ErrConnectStarted {
+ t.Fatalf("got clientEP.Connect(%#v) = %s, want = %s", remoteAddr, err, tcpip.ErrConnectStarted)
+ }
+
+ // Wait for an error due to link resolution failing, or the endpoint to be
+ // writable.
+ <-ch
+ var wOpts tcpip.WriteOptions
+ if n, err := clientEP.Write(tcpip.SlicePayload(nil), wOpts); err != test.expectedWriteErr {
+ t.Errorf("got clientEP.Write(nil, %#v) = (%d, %s), want = (_, %s)", wOpts, n, err, test.expectedWriteErr)
+ }
+
+ if test.expectedWriteErr == nil {
+ return
+ }
+
+ sockErr := sockOpts.DequeueErr()
+ if sockErr == nil {
+ t.Fatalf("got sockOpts.DequeueErr() = nil, want = non-nil")
+ }
+
+ sockErrCmpOpts := []cmp.Option{
+ cmpopts.IgnoreUnexported(tcpip.SockError{}),
+ cmp.Comparer(func(a, b *tcpip.Error) bool {
+ // tcpip.Error holds an unexported field but the errors netstack uses
+ // are pre defined so we can simply compare pointers.
+ return a == b
+ }),
+ // Ignore the payload since we do not know the TCP seq/ack numbers.
+ checker.IgnoreCmpPath(
+ "Payload",
+ ),
+ }
+
+ if addr, err := clientEP.GetLocalAddress(); err != nil {
+ t.Fatalf("clientEP.GetLocalAddress(): %s", err)
+ } else {
+ test.sockError.Offender.Port = addr.Port
+ }
+ if diff := cmp.Diff(&test.sockError, sockErr, sockErrCmpOpts...); diff != "" {
+ t.Errorf("socket error mismatch (-want +got):\n%s", diff)
+ }
+ })
+ }
+}
diff --git a/pkg/tcpip/tests/integration/loopback_test.go b/pkg/tcpip/tests/integration/loopback_test.go
index cb6169cfc..a59f25cc3 100644
--- a/pkg/tcpip/tests/integration/loopback_test.go
+++ b/pkg/tcpip/tests/integration/loopback_test.go
@@ -232,12 +232,12 @@ func TestLoopbackAcceptAllInSubnetUDP(t *testing.T) {
Port: localPort,
},
}
- n, _, err := sep.Write(tcpip.SlicePayload(data), wopts)
+ n, err := sep.Write(tcpip.SlicePayload(data), wopts)
if err != nil {
t.Fatalf("sep.Write(_, _): %s", err)
}
if want := int64(len(data)); n != want {
- t.Fatalf("got sep.Write(_, _) = (%d, _, nil), want = (%d, _, nil)", n, want)
+ t.Fatalf("got sep.Write(_, _) = (%d, nil), want = (%d, nil)", n, want)
}
var buf bytes.Buffer
diff --git a/pkg/tcpip/tests/integration/multicast_broadcast_test.go b/pkg/tcpip/tests/integration/multicast_broadcast_test.go
index b42375695..eabc87938 100644
--- a/pkg/tcpip/tests/integration/multicast_broadcast_test.go
+++ b/pkg/tcpip/tests/integration/multicast_broadcast_test.go
@@ -587,10 +587,10 @@ func TestReuseAddrAndBroadcast(t *testing.T) {
},
}
data := tcpip.SlicePayload([]byte{byte(i), 2, 3, 4})
- if n, _, err := wep.ep.Write(data, writeOpts); err != nil {
+ if n, err := wep.ep.Write(data, writeOpts); err != nil {
t.Fatalf("eps[%d].Write(_, _): %s", i, err)
} else if want := int64(len(data)); n != want {
- t.Fatalf("got eps[%d].Write(_, _) = (%d, nil, nil), want = (%d, nil, nil)", i, n, want)
+ t.Fatalf("got eps[%d].Write(_, _) = (%d, nil), want = (%d, nil)", i, n, want)
}
for j, rep := range eps {
diff --git a/pkg/tcpip/tests/integration/route_test.go b/pkg/tcpip/tests/integration/route_test.go
index 52cf89b54..76f7f54c6 100644
--- a/pkg/tcpip/tests/integration/route_test.go
+++ b/pkg/tcpip/tests/integration/route_test.go
@@ -197,10 +197,10 @@ func TestLocalPing(t *testing.T) {
payload := tcpip.SlicePayload(test.icmpBuf(t))
var wOpts tcpip.WriteOptions
- if n, _, err := ep.Write(payload, wOpts); err != nil {
+ if n, err := ep.Write(payload, wOpts); err != nil {
t.Fatalf("ep.Write(%#v, %#v): %s", payload, wOpts, err)
} else if n != int64(len(payload)) {
- t.Fatalf("got ep.Write(%#v, %#v) = (%d, _, nil), want = (%d, _, nil)", payload, wOpts, n, len(payload))
+ t.Fatalf("got ep.Write(%#v, %#v) = (%d, nil), want = (%d, nil)", payload, wOpts, n, len(payload))
}
// Wait for the endpoint to become readable.
@@ -335,14 +335,14 @@ func TestLocalUDP(t *testing.T) {
wOpts := tcpip.WriteOptions{
To: &serverAddr,
}
- if n, _, err := client.Write(clientPayload, wOpts); err != subTest.expectedWriteErr {
- t.Fatalf("got client.Write(%#v, %#v) = (%d, _, %s_), want = (_, _, %s)", clientPayload, wOpts, n, err, subTest.expectedWriteErr)
+ if n, err := client.Write(clientPayload, wOpts); err != subTest.expectedWriteErr {
+ t.Fatalf("got client.Write(%#v, %#v) = (%d, %s), want = (_, %s)", clientPayload, wOpts, n, err, subTest.expectedWriteErr)
} else if subTest.expectedWriteErr != nil {
// Nothing else to test if we expected not to be able to send the
// UDP packet.
return
} else if n != int64(len(clientPayload)) {
- t.Fatalf("got client.Write(%#v, %#v) = (%d, _, nil), want = (%d, _, nil)", clientPayload, wOpts, n, len(clientPayload))
+ t.Fatalf("got client.Write(%#v, %#v) = (%d, nil), want = (%d, nil)", clientPayload, wOpts, n, len(clientPayload))
}
}
@@ -382,10 +382,10 @@ func TestLocalUDP(t *testing.T) {
wOpts := tcpip.WriteOptions{
To: &clientAddr,
}
- if n, _, err := server.Write(serverPayload, wOpts); err != nil {
+ if n, err := server.Write(serverPayload, wOpts); err != nil {
t.Fatalf("server.Write(%#v, %#v): %s", serverPayload, wOpts, err)
} else if n != int64(len(serverPayload)) {
- t.Fatalf("got server.Write(%#v, %#v) = (%d, _, nil), want = (%d, _, nil)", serverPayload, wOpts, n, len(serverPayload))
+ t.Fatalf("got server.Write(%#v, %#v) = (%d, nil), want = (%d, nil)", serverPayload, wOpts, n, len(serverPayload))
}
}