summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/tests
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/tests')
-rw-r--r--pkg/tcpip/tests/integration/BUILD1
-rw-r--r--pkg/tcpip/tests/integration/forward_test.go46
-rw-r--r--pkg/tcpip/tests/integration/link_resolution_test.go48
-rw-r--r--pkg/tcpip/tests/integration/loopback_test.go2
-rw-r--r--pkg/tcpip/tests/integration/multicast_broadcast_test.go24
-rw-r--r--pkg/tcpip/tests/integration/route_test.go388
6 files changed, 466 insertions, 43 deletions
diff --git a/pkg/tcpip/tests/integration/BUILD b/pkg/tcpip/tests/integration/BUILD
index 34aab32d0..9b0f3b675 100644
--- a/pkg/tcpip/tests/integration/BUILD
+++ b/pkg/tcpip/tests/integration/BUILD
@@ -10,6 +10,7 @@ go_test(
"link_resolution_test.go",
"loopback_test.go",
"multicast_broadcast_test.go",
+ "route_test.go",
],
deps = [
"//pkg/tcpip",
diff --git a/pkg/tcpip/tests/integration/forward_test.go b/pkg/tcpip/tests/integration/forward_test.go
index 0dcef7b04..bf7594268 100644
--- a/pkg/tcpip/tests/integration/forward_test.go
+++ b/pkg/tcpip/tests/integration/forward_test.go
@@ -33,11 +33,6 @@ import (
func TestForwarding(t *testing.T) {
const (
- host1NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06")
- routerNIC1LinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x07")
- routerNIC2LinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x08")
- host2NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09")
-
host1NICID = 1
routerNICID1 = 2
routerNICID2 = 3
@@ -166,6 +161,38 @@ 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)
+ return endpointAndAddresses{
+ serverEP: ep1,
+ serverAddr: host2IPv4Addr.AddressWithPrefix.Address,
+ serverReadableCH: ep1WECH,
+
+ clientEP: ep2,
+ clientAddr: routerNIC1IPv4Addr.AddressWithPrefix.Address,
+ clientReadableCH: ep2WECH,
+ }
+ },
+ },
+ {
+ 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)
+ return endpointAndAddresses{
+ serverEP: ep1,
+ serverAddr: routerNIC2IPv6Addr.AddressWithPrefix.Address,
+ serverReadableCH: ep1WECH,
+
+ clientEP: ep2,
+ clientAddr: host1IPv6Addr.AddressWithPrefix.Address,
+ clientReadableCH: ep2WECH,
+ }
+ },
+ },
}
for _, test := range tests {
@@ -179,8 +206,8 @@ func TestForwarding(t *testing.T) {
routerStack := stack.New(stackOpts)
host2Stack := stack.New(stackOpts)
- host1NIC, routerNIC1 := pipe.New(host1NICLinkAddr, routerNIC1LinkAddr)
- routerNIC2, host2NIC := pipe.New(routerNIC2LinkAddr, host2NICLinkAddr)
+ host1NIC, routerNIC1 := pipe.New(linkAddr1, linkAddr2)
+ routerNIC2, host2NIC := pipe.New(linkAddr3, linkAddr4)
if err := host1Stack.CreateNIC(host1NICID, ethernet.New(host1NIC)); err != nil {
t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err)
@@ -321,12 +348,8 @@ func TestForwarding(t *testing.T) {
if err == tcpip.ErrNoLinkAddress {
// Wait for link resolution to complete.
<-ch
-
n, _, err = ep.Write(dataPayload, wOpts)
- } else if err != nil {
- t.Fatalf("ep.Write(_, _): %s", err)
}
-
if err != nil {
t.Fatalf("ep.Write(_, _): %s", err)
}
@@ -343,7 +366,6 @@ func TestForwarding(t *testing.T) {
// Wait for the endpoint to be readable.
<-ch
-
var addr tcpip.FullAddress
v, _, err := ep.Read(&addr)
if err != nil {
diff --git a/pkg/tcpip/tests/integration/link_resolution_test.go b/pkg/tcpip/tests/integration/link_resolution_test.go
index 6ddcda70c..fe7c1bb3d 100644
--- a/pkg/tcpip/tests/integration/link_resolution_test.go
+++ b/pkg/tcpip/tests/integration/link_resolution_test.go
@@ -32,32 +32,36 @@ import (
"gvisor.dev/gvisor/pkg/waiter"
)
-var (
- host1NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06")
- host2NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09")
+const (
+ linkAddr1 = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06")
+ linkAddr2 = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x07")
+ linkAddr3 = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x08")
+ linkAddr4 = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09")
+)
- host1IPv4Addr = tcpip.ProtocolAddress{
+var (
+ ipv4Addr1 = tcpip.ProtocolAddress{
Protocol: ipv4.ProtocolNumber,
AddressWithPrefix: tcpip.AddressWithPrefix{
Address: tcpip.Address(net.ParseIP("192.168.0.1").To4()),
PrefixLen: 24,
},
}
- host2IPv4Addr = tcpip.ProtocolAddress{
+ ipv4Addr2 = tcpip.ProtocolAddress{
Protocol: ipv4.ProtocolNumber,
AddressWithPrefix: tcpip.AddressWithPrefix{
Address: tcpip.Address(net.ParseIP("192.168.0.2").To4()),
PrefixLen: 8,
},
}
- host1IPv6Addr = tcpip.ProtocolAddress{
+ ipv6Addr1 = tcpip.ProtocolAddress{
Protocol: ipv6.ProtocolNumber,
AddressWithPrefix: tcpip.AddressWithPrefix{
Address: tcpip.Address(net.ParseIP("a::1").To16()),
PrefixLen: 64,
},
}
- host2IPv6Addr = tcpip.ProtocolAddress{
+ ipv6Addr2 = tcpip.ProtocolAddress{
Protocol: ipv6.ProtocolNumber,
AddressWithPrefix: tcpip.AddressWithPrefix{
Address: tcpip.Address(net.ParseIP("a::2").To16()),
@@ -89,7 +93,7 @@ func TestPing(t *testing.T) {
name: "IPv4 Ping",
transProto: icmp.ProtocolNumber4,
netProto: ipv4.ProtocolNumber,
- remoteAddr: host2IPv4Addr.AddressWithPrefix.Address,
+ remoteAddr: ipv4Addr2.AddressWithPrefix.Address,
icmpBuf: func(t *testing.T) buffer.View {
data := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
hdr := header.ICMPv4(make([]byte, header.ICMPv4MinimumSize+len(data)))
@@ -104,7 +108,7 @@ func TestPing(t *testing.T) {
name: "IPv6 Ping",
transProto: icmp.ProtocolNumber6,
netProto: ipv6.ProtocolNumber,
- remoteAddr: host2IPv6Addr.AddressWithPrefix.Address,
+ remoteAddr: ipv6Addr2.AddressWithPrefix.Address,
icmpBuf: func(t *testing.T) buffer.View {
data := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
hdr := header.ICMPv6(make([]byte, header.ICMPv6MinimumSize+len(data)))
@@ -127,7 +131,7 @@ func TestPing(t *testing.T) {
host1Stack := stack.New(stackOpts)
host2Stack := stack.New(stackOpts)
- host1NIC, host2NIC := pipe.New(host1NICLinkAddr, host2NICLinkAddr)
+ host1NIC, host2NIC := pipe.New(linkAddr1, linkAddr2)
if err := host1Stack.CreateNIC(host1NICID, ethernet.New(host1NIC)); err != nil {
t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err)
@@ -143,36 +147,36 @@ func TestPing(t *testing.T) {
t.Fatalf("host2Stack.AddAddress(%d, %d, %s): %s", host2NICID, arp.ProtocolNumber, arp.ProtocolAddress, err)
}
- if err := host1Stack.AddProtocolAddress(host1NICID, host1IPv4Addr); err != nil {
- t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, host1IPv4Addr, err)
+ if err := host1Stack.AddProtocolAddress(host1NICID, ipv4Addr1); err != nil {
+ t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, ipv4Addr1, err)
}
- if err := host2Stack.AddProtocolAddress(host2NICID, host2IPv4Addr); err != nil {
- t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, host2IPv4Addr, err)
+ if err := host2Stack.AddProtocolAddress(host2NICID, ipv4Addr2); err != nil {
+ t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, ipv4Addr2, err)
}
- if err := host1Stack.AddProtocolAddress(host1NICID, host1IPv6Addr); err != nil {
- t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, host1IPv6Addr, err)
+ if err := host1Stack.AddProtocolAddress(host1NICID, ipv6Addr1); err != nil {
+ t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, ipv6Addr1, err)
}
- if err := host2Stack.AddProtocolAddress(host2NICID, host2IPv6Addr); err != nil {
- t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, host2IPv6Addr, err)
+ if err := host2Stack.AddProtocolAddress(host2NICID, ipv6Addr2); err != nil {
+ t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, ipv6Addr2, err)
}
host1Stack.SetRouteTable([]tcpip.Route{
tcpip.Route{
- Destination: host1IPv4Addr.AddressWithPrefix.Subnet(),
+ Destination: ipv4Addr1.AddressWithPrefix.Subnet(),
NIC: host1NICID,
},
tcpip.Route{
- Destination: host1IPv6Addr.AddressWithPrefix.Subnet(),
+ Destination: ipv6Addr1.AddressWithPrefix.Subnet(),
NIC: host1NICID,
},
})
host2Stack.SetRouteTable([]tcpip.Route{
tcpip.Route{
- Destination: host2IPv4Addr.AddressWithPrefix.Subnet(),
+ Destination: ipv4Addr2.AddressWithPrefix.Subnet(),
NIC: host2NICID,
},
tcpip.Route{
- Destination: host2IPv6Addr.AddressWithPrefix.Subnet(),
+ Destination: ipv6Addr2.AddressWithPrefix.Subnet(),
NIC: host2NICID,
},
})
diff --git a/pkg/tcpip/tests/integration/loopback_test.go b/pkg/tcpip/tests/integration/loopback_test.go
index e8caf09ba..421da1add 100644
--- a/pkg/tcpip/tests/integration/loopback_test.go
+++ b/pkg/tcpip/tests/integration/loopback_test.go
@@ -204,7 +204,7 @@ func TestLoopbackAcceptAllInSubnet(t *testing.T) {
},
})
- wq := waiter.Queue{}
+ var wq waiter.Queue
rep, err := s.NewEndpoint(udp.ProtocolNumber, test.addAddress.Protocol, &wq)
if err != nil {
t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.addAddress.Protocol, err)
diff --git a/pkg/tcpip/tests/integration/multicast_broadcast_test.go b/pkg/tcpip/tests/integration/multicast_broadcast_test.go
index f1028823b..cdf0459e3 100644
--- a/pkg/tcpip/tests/integration/multicast_broadcast_test.go
+++ b/pkg/tcpip/tests/integration/multicast_broadcast_test.go
@@ -409,7 +409,7 @@ func TestIncomingMulticastAndBroadcast(t *testing.T) {
t.Fatalf("got unexpected address length = %d bytes", l)
}
- wq := waiter.Queue{}
+ var wq waiter.Queue
ep, err := s.NewEndpoint(udp.ProtocolNumber, netproto, &wq)
if err != nil {
t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, netproto, err)
@@ -447,8 +447,6 @@ func TestReuseAddrAndBroadcast(t *testing.T) {
loopbackBroadcast = tcpip.Address("\x7f\xff\xff\xff")
)
- data := tcpip.SlicePayload([]byte{1, 2, 3, 4})
-
tests := []struct {
name string
broadcastAddr tcpip.Address
@@ -492,16 +490,22 @@ func TestReuseAddrAndBroadcast(t *testing.T) {
},
})
+ type endpointAndWaiter struct {
+ ep tcpip.Endpoint
+ ch chan struct{}
+ }
+ var eps []endpointAndWaiter
// We create endpoints that bind to both the wildcard address and the
// broadcast address to make sure both of these types of "broadcast
// interested" endpoints receive broadcast packets.
- wq := waiter.Queue{}
- var eps []tcpip.Endpoint
for _, bindWildcard := range []bool{false, true} {
// Create multiple endpoints for each type of "broadcast interested"
// endpoint so we can test that all endpoints receive the broadcast
// packet.
for i := 0; i < 2; i++ {
+ var wq waiter.Queue
+ we, ch := waiter.NewChannelEntry(nil)
+ wq.EventRegister(&we, waiter.EventIn)
ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq)
if err != nil {
t.Fatalf("(eps[%d]) NewEndpoint(%d, %d, _): %s", len(eps), udp.ProtocolNumber, ipv4.ProtocolNumber, err)
@@ -528,7 +532,7 @@ func TestReuseAddrAndBroadcast(t *testing.T) {
}
}
- eps = append(eps, ep)
+ eps = append(eps, endpointAndWaiter{ep: ep, ch: ch})
}
}
@@ -539,14 +543,18 @@ func TestReuseAddrAndBroadcast(t *testing.T) {
Port: localPort,
},
}
- if n, _, err := wep.Write(data, writeOpts); err != nil {
+ data := tcpip.SlicePayload([]byte{byte(i), 2, 3, 4})
+ 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)
}
for j, rep := range eps {
- if gotPayload, _, err := rep.Read(nil); err != nil {
+ // Wait for the endpoint to become readable.
+ <-rep.ch
+
+ if gotPayload, _, err := rep.ep.Read(nil); err != nil {
t.Errorf("(eps[%d] write) eps[%d].Read(nil): %s", i, j, err)
} else if diff := cmp.Diff(buffer.View(data), gotPayload); diff != "" {
t.Errorf("(eps[%d] write) got UDP payload from eps[%d] mismatch (-want +got):\n%s", i, j, diff)
diff --git a/pkg/tcpip/tests/integration/route_test.go b/pkg/tcpip/tests/integration/route_test.go
new file mode 100644
index 000000000..02fc47015
--- /dev/null
+++ b/pkg/tcpip/tests/integration/route_test.go
@@ -0,0 +1,388 @@
+// Copyright 2020 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package integration_test
+
+import (
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "gvisor.dev/gvisor/pkg/tcpip"
+ "gvisor.dev/gvisor/pkg/tcpip/buffer"
+ "gvisor.dev/gvisor/pkg/tcpip/header"
+ "gvisor.dev/gvisor/pkg/tcpip/link/channel"
+ "gvisor.dev/gvisor/pkg/tcpip/link/loopback"
+ "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/icmp"
+ "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
+ "gvisor.dev/gvisor/pkg/waiter"
+)
+
+// TestLocalPing tests pinging a remote that is local the stack.
+//
+// This tests that a local route is created and packets do not leave the stack.
+func TestLocalPing(t *testing.T) {
+ const (
+ nicID = 1
+ ipv4Loopback = tcpip.Address("\x7f\x00\x00\x01")
+
+ // icmpDataOffset is the offset to the data in both ICMPv4 and ICMPv6 echo
+ // request/reply packets.
+ icmpDataOffset = 8
+ )
+
+ channelEP := func() stack.LinkEndpoint { return channel.New(1, header.IPv6MinimumMTU, "") }
+ channelEPCheck := func(t *testing.T, e stack.LinkEndpoint) {
+ channelEP := e.(*channel.Endpoint)
+ if n := channelEP.Drain(); n != 0 {
+ t.Fatalf("got channelEP.Drain() = %d, want = 0", n)
+ }
+ }
+
+ ipv4ICMPBuf := func(t *testing.T) buffer.View {
+ data := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
+ hdr := header.ICMPv4(make([]byte, header.ICMPv4MinimumSize+len(data)))
+ hdr.SetType(header.ICMPv4Echo)
+ if n := copy(hdr.Payload(), data[:]); n != len(data) {
+ t.Fatalf("copied %d bytes but expected to copy %d bytes", n, len(data))
+ }
+ return buffer.View(hdr)
+ }
+
+ ipv6ICMPBuf := func(t *testing.T) buffer.View {
+ data := [8]byte{1, 2, 3, 4, 5, 6, 7, 9}
+ hdr := header.ICMPv6(make([]byte, header.ICMPv6MinimumSize+len(data)))
+ hdr.SetType(header.ICMPv6EchoRequest)
+ if n := copy(hdr.Payload(), data[:]); n != len(data) {
+ t.Fatalf("copied %d bytes but expected to copy %d bytes", n, len(data))
+ }
+ return buffer.View(hdr)
+ }
+
+ tests := []struct {
+ name string
+ transProto tcpip.TransportProtocolNumber
+ netProto tcpip.NetworkProtocolNumber
+ linkEndpoint func() stack.LinkEndpoint
+ localAddr tcpip.Address
+ icmpBuf func(*testing.T) buffer.View
+ expectedConnectErr *tcpip.Error
+ checkLinkEndpoint func(t *testing.T, e stack.LinkEndpoint)
+ }{
+ {
+ name: "IPv4 loopback",
+ transProto: icmp.ProtocolNumber4,
+ netProto: ipv4.ProtocolNumber,
+ linkEndpoint: loopback.New,
+ localAddr: ipv4Loopback,
+ icmpBuf: ipv4ICMPBuf,
+ checkLinkEndpoint: func(*testing.T, stack.LinkEndpoint) {},
+ },
+ {
+ name: "IPv6 loopback",
+ transProto: icmp.ProtocolNumber6,
+ netProto: ipv6.ProtocolNumber,
+ linkEndpoint: loopback.New,
+ localAddr: header.IPv6Loopback,
+ icmpBuf: ipv6ICMPBuf,
+ checkLinkEndpoint: func(*testing.T, stack.LinkEndpoint) {},
+ },
+ {
+ name: "IPv4 non-loopback",
+ transProto: icmp.ProtocolNumber4,
+ netProto: ipv4.ProtocolNumber,
+ linkEndpoint: channelEP,
+ localAddr: ipv4Addr.Address,
+ icmpBuf: ipv4ICMPBuf,
+ checkLinkEndpoint: channelEPCheck,
+ },
+ {
+ name: "IPv6 non-loopback",
+ transProto: icmp.ProtocolNumber6,
+ netProto: ipv6.ProtocolNumber,
+ linkEndpoint: channelEP,
+ localAddr: ipv6Addr.Address,
+ icmpBuf: ipv6ICMPBuf,
+ checkLinkEndpoint: channelEPCheck,
+ },
+ {
+ name: "IPv4 loopback without local address",
+ transProto: icmp.ProtocolNumber4,
+ netProto: ipv4.ProtocolNumber,
+ linkEndpoint: loopback.New,
+ icmpBuf: ipv4ICMPBuf,
+ expectedConnectErr: tcpip.ErrNoRoute,
+ checkLinkEndpoint: func(*testing.T, stack.LinkEndpoint) {},
+ },
+ {
+ name: "IPv6 loopback without local address",
+ transProto: icmp.ProtocolNumber6,
+ netProto: ipv6.ProtocolNumber,
+ linkEndpoint: loopback.New,
+ icmpBuf: ipv6ICMPBuf,
+ expectedConnectErr: tcpip.ErrNoRoute,
+ checkLinkEndpoint: func(*testing.T, stack.LinkEndpoint) {},
+ },
+ {
+ name: "IPv4 non-loopback without local address",
+ transProto: icmp.ProtocolNumber4,
+ netProto: ipv4.ProtocolNumber,
+ linkEndpoint: channelEP,
+ icmpBuf: ipv4ICMPBuf,
+ expectedConnectErr: tcpip.ErrNoRoute,
+ checkLinkEndpoint: channelEPCheck,
+ },
+ {
+ name: "IPv6 non-loopback without local address",
+ transProto: icmp.ProtocolNumber6,
+ netProto: ipv6.ProtocolNumber,
+ linkEndpoint: channelEP,
+ icmpBuf: ipv6ICMPBuf,
+ expectedConnectErr: tcpip.ErrNoRoute,
+ checkLinkEndpoint: channelEPCheck,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ s := stack.New(stack.Options{
+ NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
+ TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol4, icmp.NewProtocol6},
+ HandleLocal: true,
+ })
+ e := test.linkEndpoint()
+ if err := s.CreateNIC(nicID, e); err != nil {
+ t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
+ }
+
+ if len(test.localAddr) != 0 {
+ if err := s.AddAddress(nicID, test.netProto, test.localAddr); err != nil {
+ t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, test.netProto, test.localAddr, err)
+ }
+ }
+
+ var wq waiter.Queue
+ we, ch := waiter.NewChannelEntry(nil)
+ wq.EventRegister(&we, waiter.EventIn)
+ ep, err := s.NewEndpoint(test.transProto, test.netProto, &wq)
+ if err != nil {
+ t.Fatalf("s.NewEndpoint(%d, %d, _): %s", test.transProto, test.netProto, err)
+ }
+ defer ep.Close()
+
+ connAddr := tcpip.FullAddress{Addr: test.localAddr}
+ if err := ep.Connect(connAddr); err != test.expectedConnectErr {
+ t.Fatalf("got ep.Connect(%#v) = %s, want = %s", connAddr, err, test.expectedConnectErr)
+ }
+
+ if test.expectedConnectErr != nil {
+ return
+ }
+
+ payload := tcpip.SlicePayload(test.icmpBuf(t))
+ var wOpts tcpip.WriteOptions
+ 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))
+ }
+
+ // Wait for the endpoint to become readable.
+ <-ch
+
+ var addr tcpip.FullAddress
+ v, _, err := ep.Read(&addr)
+ if err != nil {
+ t.Fatalf("ep.Read(_): %s", err)
+ }
+ if diff := cmp.Diff(v[icmpDataOffset:], buffer.View(payload[icmpDataOffset:])); diff != "" {
+ t.Errorf("received data mismatch (-want +got):\n%s", diff)
+ }
+ if addr.Addr != test.localAddr {
+ t.Errorf("got addr.Addr = %s, want = %s", addr.Addr, test.localAddr)
+ }
+
+ test.checkLinkEndpoint(t, e)
+ })
+ }
+}
+
+// TestLocalUDP tests sending UDP packets between two endpoints that are local
+// to the stack.
+//
+// This tests that that packets never leave the stack and the addresses
+// used when sending a packet.
+func TestLocalUDP(t *testing.T) {
+ const (
+ nicID = 1
+ )
+
+ tests := []struct {
+ name string
+ canBePrimaryAddr tcpip.ProtocolAddress
+ firstPrimaryAddr tcpip.ProtocolAddress
+ }{
+ {
+ name: "IPv4",
+ canBePrimaryAddr: ipv4Addr1,
+ firstPrimaryAddr: ipv4Addr2,
+ },
+ {
+ name: "IPv6",
+ canBePrimaryAddr: ipv6Addr1,
+ firstPrimaryAddr: ipv6Addr2,
+ },
+ }
+
+ subTests := []struct {
+ name string
+ addAddress bool
+ expectedWriteErr *tcpip.Error
+ }{
+ {
+ name: "Unassigned local address",
+ addAddress: false,
+ expectedWriteErr: tcpip.ErrNoRoute,
+ },
+ {
+ name: "Assigned local address",
+ addAddress: true,
+ expectedWriteErr: nil,
+ },
+ }
+
+ 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{ipv4.NewProtocol, ipv6.NewProtocol},
+ TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
+ HandleLocal: true,
+ }
+
+ s := stack.New(stackOpts)
+ ep := channel.New(1, header.IPv6MinimumMTU, "")
+
+ if err := s.CreateNIC(nicID, ep); err != nil {
+ t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
+ }
+
+ if subTest.addAddress {
+ if err := s.AddProtocolAddressWithOptions(nicID, test.canBePrimaryAddr, stack.CanBePrimaryEndpoint); err != nil {
+ t.Fatalf("s.AddProtocolAddressWithOptions(%d, %#v, %d): %s", nicID, test.canBePrimaryAddr, stack.FirstPrimaryEndpoint, err)
+ }
+ if err := s.AddProtocolAddressWithOptions(nicID, test.firstPrimaryAddr, stack.FirstPrimaryEndpoint); err != nil {
+ t.Fatalf("s.AddProtocolAddressWithOptions(%d, %#v, %d): %s", nicID, test.firstPrimaryAddr, stack.FirstPrimaryEndpoint, err)
+ }
+ }
+
+ var serverWQ waiter.Queue
+ serverWE, serverCH := waiter.NewChannelEntry(nil)
+ serverWQ.EventRegister(&serverWE, waiter.EventIn)
+ server, err := s.NewEndpoint(udp.ProtocolNumber, test.firstPrimaryAddr.Protocol, &serverWQ)
+ if err != nil {
+ t.Fatalf("s.NewEndpoint(%d, %d): %s", udp.ProtocolNumber, test.firstPrimaryAddr.Protocol, err)
+ }
+ defer server.Close()
+
+ bindAddr := tcpip.FullAddress{Port: 80}
+ if err := server.Bind(bindAddr); err != nil {
+ t.Fatalf("server.Bind(%#v): %s", bindAddr, err)
+ }
+
+ var clientWQ waiter.Queue
+ clientWE, clientCH := waiter.NewChannelEntry(nil)
+ clientWQ.EventRegister(&clientWE, waiter.EventIn)
+ client, err := s.NewEndpoint(udp.ProtocolNumber, test.firstPrimaryAddr.Protocol, &clientWQ)
+ if err != nil {
+ t.Fatalf("s.NewEndpoint(%d, %d): %s", udp.ProtocolNumber, test.firstPrimaryAddr.Protocol, err)
+ }
+ defer client.Close()
+
+ serverAddr := tcpip.FullAddress{
+ Addr: test.canBePrimaryAddr.AddressWithPrefix.Address,
+ Port: 80,
+ }
+
+ clientPayload := tcpip.SlicePayload([]byte{1, 2, 3, 4})
+ {
+ 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)
+ } 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))
+ }
+ }
+
+ // Wait for the server endpoint to become readable.
+ <-serverCH
+
+ var clientAddr tcpip.FullAddress
+ if v, _, err := server.Read(&clientAddr); err != nil {
+ t.Fatalf("server.Read(_): %s", err)
+ } else {
+ if diff := cmp.Diff(buffer.View(clientPayload), v); diff != "" {
+ t.Errorf("server read clientPayload mismatch (-want +got):\n%s", diff)
+ }
+ if clientAddr.Addr != test.canBePrimaryAddr.AddressWithPrefix.Address {
+ t.Errorf("got clientAddr.Addr = %s, want = %s", clientAddr.Addr, test.canBePrimaryAddr.AddressWithPrefix.Address)
+ }
+ if t.Failed() {
+ t.FailNow()
+ }
+ }
+
+ serverPayload := tcpip.SlicePayload([]byte{1, 2, 3, 4})
+ {
+ wOpts := tcpip.WriteOptions{
+ To: &clientAddr,
+ }
+ 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))
+ }
+ }
+
+ // Wait for the client endpoint to become readable.
+ <-clientCH
+
+ var gotServerAddr tcpip.FullAddress
+ if v, _, err := client.Read(&gotServerAddr); err != nil {
+ t.Fatalf("client.Read(_): %s", err)
+ } else {
+ if diff := cmp.Diff(buffer.View(serverPayload), v); diff != "" {
+ t.Errorf("client read serverPayload mismatch (-want +got):\n%s", diff)
+ }
+ if gotServerAddr.Addr != serverAddr.Addr {
+ t.Errorf("got gotServerAddr.Addr = %s, want = %s", gotServerAddr.Addr, serverAddr.Addr)
+ }
+ if t.Failed() {
+ t.FailNow()
+ }
+ }
+ })
+ }
+ })
+ }
+}