summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/tests
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/tests')
-rw-r--r--pkg/tcpip/tests/integration/BUILD131
-rw-r--r--pkg/tcpip/tests/integration/forward_test.go314
-rw-r--r--pkg/tcpip/tests/integration/iptables_test.go647
-rw-r--r--pkg/tcpip/tests/integration/link_resolution_test.go1301
-rw-r--r--pkg/tcpip/tests/integration/loopback_test.go765
-rw-r--r--pkg/tcpip/tests/integration/multicast_broadcast_test.go719
-rw-r--r--pkg/tcpip/tests/integration/route_test.go432
-rw-r--r--pkg/tcpip/tests/utils/BUILD22
-rw-r--r--pkg/tcpip/tests/utils/utils.go374
9 files changed, 0 insertions, 4705 deletions
diff --git a/pkg/tcpip/tests/integration/BUILD b/pkg/tcpip/tests/integration/BUILD
deleted file mode 100644
index 3cc8c36f1..000000000
--- a/pkg/tcpip/tests/integration/BUILD
+++ /dev/null
@@ -1,131 +0,0 @@
-load("//tools:defs.bzl", "go_test")
-
-package(licenses = ["notice"])
-
-go_test(
- name = "forward_test",
- size = "small",
- srcs = ["forward_test.go"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/checker",
- "//pkg/tcpip/network/arp",
- "//pkg/tcpip/network/ipv4",
- "//pkg/tcpip/network/ipv6",
- "//pkg/tcpip/stack",
- "//pkg/tcpip/tests/utils",
- "//pkg/tcpip/transport/tcp",
- "//pkg/tcpip/transport/udp",
- "//pkg/waiter",
- "@com_github_google_go_cmp//cmp:go_default_library",
- ],
-)
-
-go_test(
- name = "iptables_test",
- size = "small",
- srcs = ["iptables_test.go"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/header",
- "//pkg/tcpip/link/channel",
- "//pkg/tcpip/network/ipv4",
- "//pkg/tcpip/network/ipv6",
- "//pkg/tcpip/stack",
- "//pkg/tcpip/tests/utils",
- "//pkg/tcpip/transport/udp",
- ],
-)
-
-go_test(
- name = "link_resolution_test",
- size = "small",
- srcs = ["link_resolution_test.go"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/checker",
- "//pkg/tcpip/faketime",
- "//pkg/tcpip/header",
- "//pkg/tcpip/link/pipe",
- "//pkg/tcpip/network/arp",
- "//pkg/tcpip/network/ipv4",
- "//pkg/tcpip/network/ipv6",
- "//pkg/tcpip/stack",
- "//pkg/tcpip/tests/utils",
- "//pkg/tcpip/transport/icmp",
- "//pkg/tcpip/transport/tcp",
- "//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",
- ],
-)
-
-go_test(
- name = "loopback_test",
- size = "small",
- srcs = ["loopback_test.go"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/checker",
- "//pkg/tcpip/header",
- "//pkg/tcpip/link/channel",
- "//pkg/tcpip/link/loopback",
- "//pkg/tcpip/network/ipv4",
- "//pkg/tcpip/network/ipv6",
- "//pkg/tcpip/stack",
- "//pkg/tcpip/tests/utils",
- "//pkg/tcpip/transport/icmp",
- "//pkg/tcpip/transport/tcp",
- "//pkg/tcpip/transport/udp",
- "//pkg/waiter",
- "@com_github_google_go_cmp//cmp:go_default_library",
- ],
-)
-
-go_test(
- name = "multicast_broadcast_test",
- size = "small",
- srcs = ["multicast_broadcast_test.go"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/checker",
- "//pkg/tcpip/header",
- "//pkg/tcpip/link/channel",
- "//pkg/tcpip/link/loopback",
- "//pkg/tcpip/network/ipv4",
- "//pkg/tcpip/network/ipv6",
- "//pkg/tcpip/stack",
- "//pkg/tcpip/tests/utils",
- "//pkg/tcpip/transport/icmp",
- "//pkg/tcpip/transport/udp",
- "//pkg/waiter",
- "@com_github_google_go_cmp//cmp:go_default_library",
- ],
-)
-
-go_test(
- name = "route_test",
- size = "small",
- srcs = ["route_test.go"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/checker",
- "//pkg/tcpip/header",
- "//pkg/tcpip/link/channel",
- "//pkg/tcpip/link/loopback",
- "//pkg/tcpip/network/ipv4",
- "//pkg/tcpip/network/ipv6",
- "//pkg/tcpip/stack",
- "//pkg/tcpip/tests/utils",
- "//pkg/tcpip/transport/icmp",
- "//pkg/tcpip/transport/udp",
- "//pkg/waiter",
- "@com_github_google_go_cmp//cmp:go_default_library",
- ],
-)
diff --git a/pkg/tcpip/tests/integration/forward_test.go b/pkg/tcpip/tests/integration/forward_test.go
deleted file mode 100644
index 38c2f321b..000000000
--- a/pkg/tcpip/tests/integration/forward_test.go
+++ /dev/null
@@ -1,314 +0,0 @@
-// 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 forward_test
-
-import (
- "bytes"
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "gvisor.dev/gvisor/pkg/tcpip"
- "gvisor.dev/gvisor/pkg/tcpip/checker"
- "gvisor.dev/gvisor/pkg/tcpip/network/arp"
- "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/tests/utils"
- "gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
- "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
- "gvisor.dev/gvisor/pkg/waiter"
-)
-
-func TestForwarding(t *testing.T) {
- const listenPort = 8080
-
- type endpointAndAddresses struct {
- serverEP tcpip.Endpoint
- serverAddr tcpip.Address
- serverReadableCH chan struct{}
-
- clientEP tcpip.Endpoint
- clientAddr tcpip.Address
- clientReadableCH chan struct{}
- }
-
- newEP := func(t *testing.T, s *stack.Stack, transProto tcpip.TransportProtocolNumber, netProto tcpip.NetworkProtocolNumber) (tcpip.Endpoint, chan struct{}) {
- t.Helper()
- var wq waiter.Queue
- we, ch := waiter.NewChannelEntry(nil)
- wq.EventRegister(&we, waiter.EventIn)
- ep, err := s.NewEndpoint(transProto, netProto, &wq)
- if err != nil {
- t.Fatalf("s.NewEndpoint(%d, %d, _): %s", transProto, netProto, err)
- }
-
- t.Cleanup(func() {
- wq.EventUnregister(&we)
- })
-
- return ep, ch
- }
-
- tests := []struct {
- name string
- 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, 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: utils.Host1IPv4Addr.AddressWithPrefix.Address,
- serverReadableCH: ep1WECH,
-
- clientEP: ep2,
- clientAddr: utils.Host2IPv4Addr.AddressWithPrefix.Address,
- clientReadableCH: ep2WECH,
- }
- },
- },
- {
- name: "IPv6 host2 server with host1 client",
- 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: utils.Host2IPv6Addr.AddressWithPrefix.Address,
- serverReadableCH: ep1WECH,
-
- clientEP: ep2,
- clientAddr: utils.Host1IPv6Addr.AddressWithPrefix.Address,
- clientReadableCH: ep2WECH,
- }
- },
- },
- {
- name: "IPv4 host2 server with routerNIC1 client",
- 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: utils.Host2IPv4Addr.AddressWithPrefix.Address,
- serverReadableCH: ep1WECH,
-
- clientEP: ep2,
- clientAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
- clientReadableCH: ep2WECH,
- }
- },
- },
- {
- name: "IPv6 routerNIC2 server with host1 client",
- 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: utils.RouterNIC2IPv6Addr.AddressWithPrefix.Address,
- serverReadableCH: ep1WECH,
-
- clientEP: ep2,
- clientAddr: utils.Host1IPv6Addr.AddressWithPrefix.Address,
- clientReadableCH: ep2WECH,
- }
- },
- },
- }
-
- subTests := []struct {
- name string
- proto tcpip.TransportProtocolNumber
- expectedConnectErr tcpip.Error
- setupServer func(t *testing.T, ep tcpip.Endpoint)
- setupServerConn 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,
- setupServerConn: func(t *testing.T, ep tcpip.Endpoint, _ <-chan struct{}, clientAddr tcpip.FullAddress) (tcpip.Endpoint, chan struct{}) {
- t.Helper()
-
- if err := ep.Connect(clientAddr); err != nil {
- t.Fatalf("ep.Connect(%#v): %s", clientAddr, err)
- }
- return nil, nil
- },
- needRemoteAddr: true,
- },
- {
- name: "TCP",
- proto: tcp.ProtocolNumber,
- expectedConnectErr: &tcpip.ErrConnectStarted{},
- setupServer: func(t *testing.T, ep tcpip.Endpoint) {
- t.Helper()
-
- if err := ep.Listen(1); err != nil {
- t.Fatalf("ep.Listen(1): %s", err)
- }
- },
- setupServerConn: func(t *testing.T, ep tcpip.Endpoint, ch <-chan struct{}, clientAddr tcpip.FullAddress) (tcpip.Endpoint, chan struct{}) {
- t.Helper()
-
- var addr tcpip.FullAddress
- for {
- newEP, wq, err := ep.Accept(&addr)
- if _, ok := err.(*tcpip.ErrWouldBlock); ok {
- <-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,
- },
- }
-
- 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)
- utils.SetupRoutedStacks(t, host1Stack, routerStack, host2Stack)
-
- 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 subTest.setupServer != nil {
- subTest.setupServer(t, epsAndAddrs.serverEP)
- }
- {
- err := epsAndAddrs.clientEP.Connect(serverAddr)
- if diff := cmp.Diff(subTest.expectedConnectErr, err); diff != "" {
- t.Fatalf("unexpected error from epsAndAddrs.clientEP.Connect(%#v), (-want, +got):\n%s", serverAddr, diff)
- }
- }
- 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.setupServerConn(t, serverEP, serverCH, clientAddr); ep != nil {
- defer ep.Close()
- serverEP = ep
- serverCH = ch
- }
-
- write := func(ep tcpip.Endpoint, data []byte) {
- t.Helper()
-
- var r bytes.Reader
- r.Reset(data)
- var wOpts tcpip.WriteOptions
- n, err := ep.Write(&r, 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()
-
- var buf bytes.Buffer
- var res tcpip.ReadResult
- for {
- var err tcpip.Error
- opts := tcpip.ReadOptions{NeedRemoteAddr: subTest.needRemoteAddr}
- res, err = ep.Read(&buf, opts)
- if _, ok := err.(*tcpip.ErrWouldBlock); ok {
- <-ch
- continue
- }
- if err != nil {
- t.Fatalf("ep.Read(_, %d, %#v): %s", len(data), opts, err)
- }
- break
- }
-
- 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 = []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/iptables_test.go b/pkg/tcpip/tests/integration/iptables_test.go
deleted file mode 100644
index 480174070..000000000
--- a/pkg/tcpip/tests/integration/iptables_test.go
+++ /dev/null
@@ -1,647 +0,0 @@
-// Copyright 2021 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 iptables_test
-
-import (
- "testing"
-
- "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/network/ipv4"
- "gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
- "gvisor.dev/gvisor/pkg/tcpip/stack"
- "gvisor.dev/gvisor/pkg/tcpip/tests/utils"
- "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
-)
-
-type inputIfNameMatcher struct {
- name string
-}
-
-var _ stack.Matcher = (*inputIfNameMatcher)(nil)
-
-func (*inputIfNameMatcher) Name() string {
- return "inputIfNameMatcher"
-}
-
-func (im *inputIfNameMatcher) Match(hook stack.Hook, _ *stack.PacketBuffer, inNicName, _ string) (bool, bool) {
- return (hook == stack.Input && im.name != "" && im.name == inNicName), false
-}
-
-const (
- nicID = 1
- nicName = "nic1"
- anotherNicName = "nic2"
- linkAddr = tcpip.LinkAddress("\x0a\x0b\x0c\x0d\x0e\x0e")
- srcAddrV4 = "\x0a\x00\x00\x01"
- dstAddrV4 = "\x0a\x00\x00\x02"
- srcAddrV6 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
- dstAddrV6 = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
- payloadSize = 20
-)
-
-func genStackV6(t *testing.T) (*stack.Stack, *channel.Endpoint) {
- t.Helper()
- s := stack.New(stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{ipv6.NewProtocol},
- })
- e := channel.New(0, header.IPv6MinimumMTU, linkAddr)
- nicOpts := stack.NICOptions{Name: nicName}
- if err := s.CreateNICWithOptions(nicID, e, nicOpts); err != nil {
- t.Fatalf("CreateNICWithOptions(%d, _, %#v) = %s", nicID, nicOpts, err)
- }
- if err := s.AddAddress(nicID, header.IPv6ProtocolNumber, dstAddrV6); err != nil {
- t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, header.IPv6ProtocolNumber, dstAddrV6, err)
- }
- return s, e
-}
-
-func genStackV4(t *testing.T) (*stack.Stack, *channel.Endpoint) {
- t.Helper()
- s := stack.New(stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol},
- })
- e := channel.New(0, header.IPv4MinimumMTU, linkAddr)
- nicOpts := stack.NICOptions{Name: nicName}
- if err := s.CreateNICWithOptions(nicID, e, nicOpts); err != nil {
- t.Fatalf("CreateNICWithOptions(%d, _, %#v) = %s", nicID, nicOpts, err)
- }
- if err := s.AddAddress(nicID, header.IPv4ProtocolNumber, dstAddrV4); err != nil {
- t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, header.IPv4ProtocolNumber, dstAddrV4, err)
- }
- return s, e
-}
-
-func genPacketV6() *stack.PacketBuffer {
- pktSize := header.IPv6MinimumSize + payloadSize
- hdr := buffer.NewPrependable(pktSize)
- ip := header.IPv6(hdr.Prepend(pktSize))
- ip.Encode(&header.IPv6Fields{
- PayloadLength: payloadSize,
- TransportProtocol: 99,
- HopLimit: 255,
- SrcAddr: srcAddrV6,
- DstAddr: dstAddrV6,
- })
- vv := hdr.View().ToVectorisedView()
- return stack.NewPacketBuffer(stack.PacketBufferOptions{Data: vv})
-}
-
-func genPacketV4() *stack.PacketBuffer {
- pktSize := header.IPv4MinimumSize + payloadSize
- hdr := buffer.NewPrependable(pktSize)
- ip := header.IPv4(hdr.Prepend(pktSize))
- ip.Encode(&header.IPv4Fields{
- TOS: 0,
- TotalLength: uint16(pktSize),
- ID: 1,
- Flags: 0,
- FragmentOffset: 16,
- TTL: 48,
- Protocol: 99,
- SrcAddr: srcAddrV4,
- DstAddr: dstAddrV4,
- })
- ip.SetChecksum(0)
- ip.SetChecksum(^ip.CalculateChecksum())
- vv := hdr.View().ToVectorisedView()
- return stack.NewPacketBuffer(stack.PacketBufferOptions{Data: vv})
-}
-
-func TestIPTablesStatsForInput(t *testing.T) {
- tests := []struct {
- name string
- setupStack func(*testing.T) (*stack.Stack, *channel.Endpoint)
- setupFilter func(*testing.T, *stack.Stack)
- genPacket func() *stack.PacketBuffer
- proto tcpip.NetworkProtocolNumber
- expectReceived int
- expectInputDropped int
- }{
- {
- name: "IPv6 Accept",
- setupStack: genStackV6,
- setupFilter: func(*testing.T, *stack.Stack) { /* no filter */ },
- genPacket: genPacketV6,
- proto: header.IPv6ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 0,
- },
- {
- name: "IPv4 Accept",
- setupStack: genStackV4,
- setupFilter: func(*testing.T, *stack.Stack) { /* no filter */ },
- genPacket: genPacketV4,
- proto: header.IPv4ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 0,
- },
- {
- name: "IPv6 Drop (input interface matches)",
- setupStack: genStackV6,
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
- ipt := s.IPTables()
- filter := ipt.GetTable(stack.FilterID, true /* ipv6 */)
- ruleIdx := filter.BuiltinChains[stack.Input]
- filter.Rules[ruleIdx].Filter = stack.IPHeaderFilter{InputInterface: nicName}
- filter.Rules[ruleIdx].Target = &stack.DropTarget{}
- filter.Rules[ruleIdx].Matchers = []stack.Matcher{&inputIfNameMatcher{nicName}}
- // Make sure the packet is not dropped by the next rule.
- filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
- if err := ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */); err != nil {
- t.Fatalf("ipt.RelaceTable(%d, _, %t): %s", stack.FilterID, true, err)
- }
- },
- genPacket: genPacketV6,
- proto: header.IPv6ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 1,
- },
- {
- name: "IPv4 Drop (input interface matches)",
- setupStack: genStackV4,
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
- ipt := s.IPTables()
- filter := ipt.GetTable(stack.FilterID, false /* ipv6 */)
- ruleIdx := filter.BuiltinChains[stack.Input]
- filter.Rules[ruleIdx].Filter = stack.IPHeaderFilter{InputInterface: nicName}
- filter.Rules[ruleIdx].Target = &stack.DropTarget{}
- filter.Rules[ruleIdx].Matchers = []stack.Matcher{&inputIfNameMatcher{nicName}}
- filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
- if err := ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */); err != nil {
- t.Fatalf("ipt.RelaceTable(%d, _, %t): %s", stack.FilterID, false, err)
- }
- },
- genPacket: genPacketV4,
- proto: header.IPv4ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 1,
- },
- {
- name: "IPv6 Accept (input interface does not match)",
- setupStack: genStackV6,
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
- ipt := s.IPTables()
- filter := ipt.GetTable(stack.FilterID, true /* ipv6 */)
- ruleIdx := filter.BuiltinChains[stack.Input]
- filter.Rules[ruleIdx].Filter = stack.IPHeaderFilter{InputInterface: anotherNicName}
- filter.Rules[ruleIdx].Target = &stack.DropTarget{}
- filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
- if err := ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */); err != nil {
- t.Fatalf("ipt.RelaceTable(%d, _, %t): %s", stack.FilterID, true, err)
- }
- },
- genPacket: genPacketV6,
- proto: header.IPv6ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 0,
- },
- {
- name: "IPv4 Accept (input interface does not match)",
- setupStack: genStackV4,
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
- ipt := s.IPTables()
- filter := ipt.GetTable(stack.FilterID, false /* ipv6 */)
- ruleIdx := filter.BuiltinChains[stack.Input]
- filter.Rules[ruleIdx].Filter = stack.IPHeaderFilter{InputInterface: anotherNicName}
- filter.Rules[ruleIdx].Target = &stack.DropTarget{}
- filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
- if err := ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */); err != nil {
- t.Fatalf("ipt.RelaceTable(%d, _, %t): %s", stack.FilterID, false, err)
- }
- },
- genPacket: genPacketV4,
- proto: header.IPv4ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 0,
- },
- {
- name: "IPv6 Drop (input interface does not match but invert is true)",
- setupStack: genStackV6,
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
- ipt := s.IPTables()
- filter := ipt.GetTable(stack.FilterID, true /* ipv6 */)
- ruleIdx := filter.BuiltinChains[stack.Input]
- filter.Rules[ruleIdx].Filter = stack.IPHeaderFilter{
- InputInterface: anotherNicName,
- InputInterfaceInvert: true,
- }
- filter.Rules[ruleIdx].Target = &stack.DropTarget{}
- filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
- if err := ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */); err != nil {
- t.Fatalf("ipt.RelaceTable(%d, _, %t): %s", stack.FilterID, true, err)
- }
- },
- genPacket: genPacketV6,
- proto: header.IPv6ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 1,
- },
- {
- name: "IPv4 Drop (input interface does not match but invert is true)",
- setupStack: genStackV4,
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
- ipt := s.IPTables()
- filter := ipt.GetTable(stack.FilterID, false /* ipv6 */)
- ruleIdx := filter.BuiltinChains[stack.Input]
- filter.Rules[ruleIdx].Filter = stack.IPHeaderFilter{
- InputInterface: anotherNicName,
- InputInterfaceInvert: true,
- }
- filter.Rules[ruleIdx].Target = &stack.DropTarget{}
- filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
- if err := ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */); err != nil {
- t.Fatalf("ipt.RelaceTable(%d, _, %t): %s", stack.FilterID, false, err)
- }
- },
- genPacket: genPacketV4,
- proto: header.IPv4ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 1,
- },
- {
- name: "IPv6 Accept (input interface does not match using a matcher)",
- setupStack: genStackV6,
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
- ipt := s.IPTables()
- filter := ipt.GetTable(stack.FilterID, true /* ipv6 */)
- ruleIdx := filter.BuiltinChains[stack.Input]
- filter.Rules[ruleIdx].Target = &stack.DropTarget{}
- filter.Rules[ruleIdx].Matchers = []stack.Matcher{&inputIfNameMatcher{anotherNicName}}
- filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
- if err := ipt.ReplaceTable(stack.FilterID, filter, true /* ipv6 */); err != nil {
- t.Fatalf("ipt.RelaceTable(%d, _, %t): %s", stack.FilterID, true, err)
- }
- },
- genPacket: genPacketV6,
- proto: header.IPv6ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 0,
- },
- {
- name: "IPv4 Accept (input interface does not match using a matcher)",
- setupStack: genStackV4,
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
- ipt := s.IPTables()
- filter := ipt.GetTable(stack.FilterID, false /* ipv6 */)
- ruleIdx := filter.BuiltinChains[stack.Input]
- filter.Rules[ruleIdx].Target = &stack.DropTarget{}
- filter.Rules[ruleIdx].Matchers = []stack.Matcher{&inputIfNameMatcher{anotherNicName}}
- filter.Rules[ruleIdx+1].Target = &stack.AcceptTarget{}
- if err := ipt.ReplaceTable(stack.FilterID, filter, false /* ipv6 */); err != nil {
- t.Fatalf("ipt.RelaceTable(%d, _, %t): %s", stack.FilterID, false, err)
- }
- },
- genPacket: genPacketV4,
- proto: header.IPv4ProtocolNumber,
- expectReceived: 1,
- expectInputDropped: 0,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- s, e := test.setupStack(t)
- test.setupFilter(t, s)
- e.InjectInbound(test.proto, test.genPacket())
-
- if got := int(s.Stats().IP.PacketsReceived.Value()); got != test.expectReceived {
- t.Errorf("got PacketReceived = %d, want = %d", got, test.expectReceived)
- }
- if got := int(s.Stats().IP.IPTablesInputDropped.Value()); got != test.expectInputDropped {
- t.Errorf("got IPTablesInputDropped = %d, want = %d", got, test.expectInputDropped)
- }
- })
- }
-}
-
-var _ stack.LinkEndpoint = (*channelEndpointWithoutWritePacket)(nil)
-
-// channelEndpointWithoutWritePacket is a channel endpoint that does not support
-// stack.LinkEndpoint.WritePacket.
-type channelEndpointWithoutWritePacket struct {
- *channel.Endpoint
-
- t *testing.T
-}
-
-func (c *channelEndpointWithoutWritePacket) WritePacket(stack.RouteInfo, *stack.GSO, tcpip.NetworkProtocolNumber, *stack.PacketBuffer) tcpip.Error {
- c.t.Error("unexpectedly called WritePacket; all writes should go through WritePackets")
- return &tcpip.ErrNotSupported{}
-}
-
-var _ stack.Matcher = (*udpSourcePortMatcher)(nil)
-
-type udpSourcePortMatcher struct {
- port uint16
-}
-
-func (*udpSourcePortMatcher) Name() string {
- return "udpSourcePortMatcher"
-}
-
-func (m *udpSourcePortMatcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string) (matches, hotdrop bool) {
- udp := header.UDP(pkt.TransportHeader().View())
- if len(udp) < header.UDPMinimumSize {
- // Drop immediately as the packet is invalid.
- return false, true
- }
-
- return udp.SourcePort() == m.port, false
-}
-
-func TestIPTableWritePackets(t *testing.T) {
- const (
- nicID = 1
-
- dropLocalPort = utils.LocalPort - 1
- acceptPackets = 2
- dropPackets = 3
- )
-
- udpHdr := func(hdr buffer.View, srcAddr, dstAddr tcpip.Address, srcPort, dstPort uint16) {
- u := header.UDP(hdr)
- u.Encode(&header.UDPFields{
- SrcPort: srcPort,
- DstPort: dstPort,
- Length: header.UDPMinimumSize,
- })
- sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, srcAddr, dstAddr, header.UDPMinimumSize)
- sum = header.Checksum(hdr, sum)
- u.SetChecksum(^u.CalculateChecksum(sum))
- }
-
- tests := []struct {
- name string
- setupFilter func(*testing.T, *stack.Stack)
- genPacket func(*stack.Route) stack.PacketBufferList
- proto tcpip.NetworkProtocolNumber
- remoteAddr tcpip.Address
- expectSent uint64
- expectOutputDropped uint64
- }{
- {
- name: "IPv4 Accept",
- setupFilter: func(*testing.T, *stack.Stack) { /* no filter */ },
- genPacket: func(r *stack.Route) stack.PacketBufferList {
- var pkts stack.PacketBufferList
-
- pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: int(r.MaxHeaderLength() + header.UDPMinimumSize),
- })
- hdr := pkt.TransportHeader().Push(header.UDPMinimumSize)
- udpHdr(hdr, r.LocalAddress, r.RemoteAddress, utils.LocalPort, utils.RemotePort)
- pkts.PushFront(pkt)
-
- return pkts
- },
- proto: header.IPv4ProtocolNumber,
- remoteAddr: dstAddrV4,
- expectSent: 1,
- expectOutputDropped: 0,
- },
- {
- name: "IPv4 Drop Other Port",
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
-
- table := stack.Table{
- Rules: []stack.Rule{
- {
- Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber},
- },
- {
- Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber},
- },
- {
- Matchers: []stack.Matcher{&udpSourcePortMatcher{port: dropLocalPort}},
- Target: &stack.DropTarget{NetworkProtocol: header.IPv4ProtocolNumber},
- },
- {
- Target: &stack.AcceptTarget{NetworkProtocol: header.IPv4ProtocolNumber},
- },
- {
- Target: &stack.ErrorTarget{NetworkProtocol: header.IPv4ProtocolNumber},
- },
- },
- BuiltinChains: [stack.NumHooks]int{
- stack.Prerouting: stack.HookUnset,
- stack.Input: 0,
- stack.Forward: 1,
- stack.Output: 2,
- stack.Postrouting: stack.HookUnset,
- },
- Underflows: [stack.NumHooks]int{
- stack.Prerouting: stack.HookUnset,
- stack.Input: 0,
- stack.Forward: 1,
- stack.Output: 2,
- stack.Postrouting: stack.HookUnset,
- },
- }
-
- if err := s.IPTables().ReplaceTable(stack.FilterID, table, false /* ipv4 */); err != nil {
- t.Fatalf("RelaceTable(%d, _, false): %s", stack.FilterID, err)
- }
- },
- genPacket: func(r *stack.Route) stack.PacketBufferList {
- var pkts stack.PacketBufferList
-
- for i := 0; i < acceptPackets; i++ {
- pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: int(r.MaxHeaderLength() + header.UDPMinimumSize),
- })
- hdr := pkt.TransportHeader().Push(header.UDPMinimumSize)
- udpHdr(hdr, r.LocalAddress, r.RemoteAddress, utils.LocalPort, utils.RemotePort)
- pkts.PushFront(pkt)
- }
- for i := 0; i < dropPackets; i++ {
- pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: int(r.MaxHeaderLength() + header.UDPMinimumSize),
- })
- hdr := pkt.TransportHeader().Push(header.UDPMinimumSize)
- udpHdr(hdr, r.LocalAddress, r.RemoteAddress, dropLocalPort, utils.RemotePort)
- pkts.PushFront(pkt)
- }
-
- return pkts
- },
- proto: header.IPv4ProtocolNumber,
- remoteAddr: dstAddrV4,
- expectSent: acceptPackets,
- expectOutputDropped: dropPackets,
- },
- {
- name: "IPv6 Accept",
- setupFilter: func(*testing.T, *stack.Stack) { /* no filter */ },
- genPacket: func(r *stack.Route) stack.PacketBufferList {
- var pkts stack.PacketBufferList
-
- pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: int(r.MaxHeaderLength() + header.UDPMinimumSize),
- })
- hdr := pkt.TransportHeader().Push(header.UDPMinimumSize)
- udpHdr(hdr, r.LocalAddress, r.RemoteAddress, utils.LocalPort, utils.RemotePort)
- pkts.PushFront(pkt)
-
- return pkts
- },
- proto: header.IPv6ProtocolNumber,
- remoteAddr: dstAddrV6,
- expectSent: 1,
- expectOutputDropped: 0,
- },
- {
- name: "IPv6 Drop Other Port",
- setupFilter: func(t *testing.T, s *stack.Stack) {
- t.Helper()
-
- table := stack.Table{
- Rules: []stack.Rule{
- {
- Target: &stack.AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber},
- },
- {
- Target: &stack.AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber},
- },
- {
- Matchers: []stack.Matcher{&udpSourcePortMatcher{port: dropLocalPort}},
- Target: &stack.DropTarget{NetworkProtocol: header.IPv6ProtocolNumber},
- },
- {
- Target: &stack.AcceptTarget{NetworkProtocol: header.IPv6ProtocolNumber},
- },
- {
- Target: &stack.ErrorTarget{NetworkProtocol: header.IPv6ProtocolNumber},
- },
- },
- BuiltinChains: [stack.NumHooks]int{
- stack.Prerouting: stack.HookUnset,
- stack.Input: 0,
- stack.Forward: 1,
- stack.Output: 2,
- stack.Postrouting: stack.HookUnset,
- },
- Underflows: [stack.NumHooks]int{
- stack.Prerouting: stack.HookUnset,
- stack.Input: 0,
- stack.Forward: 1,
- stack.Output: 2,
- stack.Postrouting: stack.HookUnset,
- },
- }
-
- if err := s.IPTables().ReplaceTable(stack.FilterID, table, true /* ipv6 */); err != nil {
- t.Fatalf("RelaceTable(%d, _, true): %s", stack.FilterID, err)
- }
- },
- genPacket: func(r *stack.Route) stack.PacketBufferList {
- var pkts stack.PacketBufferList
-
- for i := 0; i < acceptPackets; i++ {
- pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: int(r.MaxHeaderLength() + header.UDPMinimumSize),
- })
- hdr := pkt.TransportHeader().Push(header.UDPMinimumSize)
- udpHdr(hdr, r.LocalAddress, r.RemoteAddress, utils.LocalPort, utils.RemotePort)
- pkts.PushFront(pkt)
- }
- for i := 0; i < dropPackets; i++ {
- pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: int(r.MaxHeaderLength() + header.UDPMinimumSize),
- })
- hdr := pkt.TransportHeader().Push(header.UDPMinimumSize)
- udpHdr(hdr, r.LocalAddress, r.RemoteAddress, dropLocalPort, utils.RemotePort)
- pkts.PushFront(pkt)
- }
-
- return pkts
- },
- proto: header.IPv6ProtocolNumber,
- remoteAddr: dstAddrV6,
- expectSent: acceptPackets,
- expectOutputDropped: dropPackets,
- },
- }
-
- 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{udp.NewProtocol},
- })
- e := channelEndpointWithoutWritePacket{
- Endpoint: channel.New(4, header.IPv6MinimumMTU, linkAddr),
- t: t,
- }
- if err := s.CreateNIC(nicID, &e); err != nil {
- t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
- }
- if err := s.AddAddress(nicID, header.IPv6ProtocolNumber, srcAddrV6); err != nil {
- t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, header.IPv6ProtocolNumber, srcAddrV6, err)
- }
- if err := s.AddAddress(nicID, header.IPv4ProtocolNumber, srcAddrV4); err != nil {
- t.Fatalf("AddAddress(%d, %d, %s) = %s", nicID, header.IPv4ProtocolNumber, srcAddrV4, err)
- }
-
- s.SetRouteTable([]tcpip.Route{
- {
- Destination: header.IPv4EmptySubnet,
- NIC: nicID,
- },
- {
- Destination: header.IPv6EmptySubnet,
- NIC: nicID,
- },
- })
-
- test.setupFilter(t, s)
-
- r, err := s.FindRoute(nicID, "", test.remoteAddr, test.proto, false)
- if err != nil {
- t.Fatalf("FindRoute(%d, '', %s, %d, false): %s", nicID, test.remoteAddr, test.proto, err)
- }
- defer r.Release()
-
- pkts := test.genPacket(r)
- pktsLen := pkts.Len()
- if n, err := r.WritePackets(nil /* gso */, pkts, stack.NetworkHeaderParams{
- Protocol: header.UDPProtocolNumber,
- TTL: 64,
- }); err != nil {
- t.Fatalf("WritePackets(...): %s", err)
- } else if n != pktsLen {
- t.Fatalf("got WritePackets(...) = %d, want = %d", n, pktsLen)
- }
-
- if got := s.Stats().IP.PacketsSent.Value(); got != test.expectSent {
- t.Errorf("got PacketSent = %d, want = %d", got, test.expectSent)
- }
- if got := s.Stats().IP.IPTablesOutputDropped.Value(); got != test.expectOutputDropped {
- t.Errorf("got IPTablesOutputDropped = %d, want = %d", got, test.expectOutputDropped)
- }
- })
- }
-}
diff --git a/pkg/tcpip/tests/integration/link_resolution_test.go b/pkg/tcpip/tests/integration/link_resolution_test.go
deleted file mode 100644
index 095623789..000000000
--- a/pkg/tcpip/tests/integration/link_resolution_test.go
+++ /dev/null
@@ -1,1301 +0,0 @@
-// 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 link_resolution_test
-
-import (
- "bytes"
- "fmt"
- "testing"
- "time"
-
- "github.com/google/go-cmp/cmp"
- "github.com/google/go-cmp/cmp/cmpopts"
- "gvisor.dev/gvisor/pkg/tcpip"
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
- "gvisor.dev/gvisor/pkg/tcpip/checker"
- "gvisor.dev/gvisor/pkg/tcpip/faketime"
- "gvisor.dev/gvisor/pkg/tcpip/header"
- "gvisor.dev/gvisor/pkg/tcpip/link/pipe"
- "gvisor.dev/gvisor/pkg/tcpip/network/arp"
- "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/tests/utils"
- "gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
- "gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
- "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
- "gvisor.dev/gvisor/pkg/waiter"
-)
-
-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(utils.LinkAddr1, utils.LinkAddr2)
-
- if err := host1Stack.CreateNIC(host1NICID, utils.NewEthernetEndpoint(host1NIC)); err != nil {
- t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err)
- }
- if err := host2Stack.CreateNIC(host2NICID, utils.NewEthernetEndpoint(host2NIC)); err != nil {
- t.Fatalf("host2Stack.CreateNIC(%d, _): %s", host2NICID, err)
- }
-
- if err := host1Stack.AddProtocolAddress(host1NICID, utils.Ipv4Addr1); err != nil {
- t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, utils.Ipv4Addr1, err)
- }
- if err := host2Stack.AddProtocolAddress(host2NICID, utils.Ipv4Addr2); err != nil {
- t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, utils.Ipv4Addr2, err)
- }
- if err := host1Stack.AddProtocolAddress(host1NICID, utils.Ipv6Addr1); err != nil {
- t.Fatalf("host1Stack.AddProtocolAddress(%d, %#v): %s", host1NICID, utils.Ipv6Addr1, err)
- }
- if err := host2Stack.AddProtocolAddress(host2NICID, utils.Ipv6Addr2); err != nil {
- t.Fatalf("host2Stack.AddProtocolAddress(%d, %#v): %s", host2NICID, utils.Ipv6Addr2, err)
- }
-
- host1Stack.SetRouteTable([]tcpip.Route{
- {
- Destination: utils.Ipv4Addr1.AddressWithPrefix.Subnet(),
- NIC: host1NICID,
- },
- {
- Destination: utils.Ipv6Addr1.AddressWithPrefix.Subnet(),
- NIC: host1NICID,
- },
- })
- host2Stack.SetRouteTable([]tcpip.Route{
- {
- Destination: utils.Ipv4Addr2.AddressWithPrefix.Subnet(),
- NIC: host2NICID,
- },
- {
- Destination: utils.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) {
- const (
- host1NICID = 1
- host2NICID = 4
-
- // icmpDataOffset is the offset to the data in both ICMPv4 and ICMPv6 echo
- // request/reply packets.
- icmpDataOffset = 8
- )
-
- tests := []struct {
- name string
- transProto tcpip.TransportProtocolNumber
- netProto tcpip.NetworkProtocolNumber
- remoteAddr tcpip.Address
- icmpBuf func(*testing.T) []byte
- }{
- {
- name: "IPv4 Ping",
- transProto: icmp.ProtocolNumber4,
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr2.AddressWithPrefix.Address,
- icmpBuf: func(t *testing.T) []byte {
- 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 hdr
- },
- },
- {
- name: "IPv6 Ping",
- transProto: icmp.ProtocolNumber6,
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr2.AddressWithPrefix.Address,
- icmpBuf: func(t *testing.T) []byte {
- data := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
- 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 hdr
- },
- },
- }
-
- 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{icmp.NewProtocol4, icmp.NewProtocol6},
- }
-
- host1Stack, _ := setupStack(t, stackOpts, host1NICID, host2NICID)
-
- var wq waiter.Queue
- we, waiterCH := waiter.NewChannelEntry(nil)
- wq.EventRegister(&we, waiter.EventIn)
- ep, err := host1Stack.NewEndpoint(test.transProto, test.netProto, &wq)
- if err != nil {
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", test.transProto, test.netProto, err)
- }
- defer ep.Close()
-
- icmpBuf := test.icmpBuf(t)
- var r bytes.Reader
- r.Reset(icmpBuf)
- wOpts := tcpip.WriteOptions{To: &tcpip.FullAddress{Addr: test.remoteAddr}}
- if n, err := ep.Write(&r, 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)
- }
-
- // Wait for the endpoint to be readable.
- <-waiterCH
-
- var buf bytes.Buffer
- opts := tcpip.ReadOptions{NeedRemoteAddr: true}
- res, err := ep.Read(&buf, opts)
- if err != nil {
- t.Fatalf("ep.Read(_, %d, %#v): %s", len(icmpBuf), opts, err)
- }
- if diff := cmp.Diff(tcpip.ReadResult{
- Count: buf.Len(),
- Total: buf.Len(),
- RemoteAddr: tcpip.FullAddress{Addr: test.remoteAddr},
- }, 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()[icmpDataOffset:], icmpBuf[icmpDataOffset:]); diff != "" {
- t.Errorf("received data mismatch (-want +got):\n%s", diff)
- }
- })
- }
-}
-
-type transportError struct {
- origin tcpip.SockErrOrigin
- typ uint8
- code uint8
- info uint32
- kind stack.TransportErrorKind
-}
-
-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
- transErr transportError
- }{
- {
- name: "IPv4 with resolvable remote",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr2.AddressWithPrefix.Address,
- expectedWriteErr: nil,
- },
- {
- name: "IPv6 with resolvable remote",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr2.AddressWithPrefix.Address,
- expectedWriteErr: nil,
- },
- {
- name: "IPv4 without resolvable remote",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr3.AddressWithPrefix.Address,
- expectedWriteErr: &tcpip.ErrNoRoute{},
- sockError: tcpip.SockError{
- Err: &tcpip.ErrNoRoute{},
- Dst: tcpip.FullAddress{
- NIC: host1NICID,
- Addr: utils.Ipv4Addr3.AddressWithPrefix.Address,
- Port: 1234,
- },
- Offender: tcpip.FullAddress{
- NIC: host1NICID,
- Addr: utils.Ipv4Addr1.AddressWithPrefix.Address,
- },
- NetProto: ipv4.ProtocolNumber,
- },
- transErr: transportError{
- origin: tcpip.SockExtErrorOriginICMP,
- typ: uint8(header.ICMPv4DstUnreachable),
- code: uint8(header.ICMPv4HostUnreachable),
- kind: stack.DestinationHostUnreachableTransportError,
- },
- },
- {
- name: "IPv6 without resolvable remote",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr3.AddressWithPrefix.Address,
- expectedWriteErr: &tcpip.ErrNoRoute{},
- sockError: tcpip.SockError{
- Err: &tcpip.ErrNoRoute{},
- Dst: tcpip.FullAddress{
- NIC: host1NICID,
- Addr: utils.Ipv6Addr3.AddressWithPrefix.Address,
- Port: 1234,
- },
- Offender: tcpip.FullAddress{
- NIC: host1NICID,
- Addr: utils.Ipv6Addr1.AddressWithPrefix.Address,
- },
- NetProto: ipv6.ProtocolNumber,
- },
- transErr: transportError{
- origin: tcpip.SockExtErrorOriginICMP6,
- typ: uint8(header.ICMPv6DstUnreachable),
- code: uint8(header.ICMPv6AddressUnreachable),
- kind: stack.DestinationHostUnreachableTransportError,
- },
- },
- }
-
- 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
- {
- err := clientEP.Connect(remoteAddr)
- if _, ok := err.(*tcpip.ErrConnectStarted); !ok {
- 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 r bytes.Reader
- r.Reset([]byte{0})
- var wOpts tcpip.WriteOptions
- _, err := clientEP.Write(&r, wOpts)
- if diff := cmp.Diff(test.expectedWriteErr, err); diff != "" {
- t.Errorf("unexpected error from clientEP.Write(_, %#v), (-want, +got):\n%s", wOpts, diff)
- }
- }
-
- 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
- }),
- checker.IgnoreCmpPath(
- // Ignore the payload since we do not know the TCP seq/ack numbers.
- "Payload",
- // Ignore the cause since we will compare its properties separately
- // since the concrete type of the cause is unknown.
- "Cause",
- ),
- }
-
- 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)
- }
-
- transErr, ok := sockErr.Cause.(stack.TransportError)
- if !ok {
- t.Fatalf("socket error cause is not a transport error; cause = %#v", sockErr.Cause)
- }
- if diff := cmp.Diff(
- test.transErr,
- transportError{
- origin: transErr.Origin(),
- typ: transErr.Type(),
- code: transErr.Code(),
- info: transErr.Info(),
- kind: transErr.Kind(),
- },
- cmp.AllowUnexported(transportError{}),
- ); diff != "" {
- t.Errorf("socket error mismatch (-want +got):\n%s", diff)
- }
- })
- }
-}
-
-func TestGetLinkAddress(t *testing.T) {
- const (
- host1NICID = 1
- host2NICID = 4
- )
-
- tests := []struct {
- name string
- netProto tcpip.NetworkProtocolNumber
- remoteAddr, localAddr tcpip.Address
- expectedErr tcpip.Error
- }{
- {
- name: "IPv4 resolvable",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr2.AddressWithPrefix.Address,
- expectedErr: nil,
- },
- {
- name: "IPv6 resolvable",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr2.AddressWithPrefix.Address,
- expectedErr: nil,
- },
- {
- name: "IPv4 not resolvable",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr3.AddressWithPrefix.Address,
- expectedErr: &tcpip.ErrTimeout{},
- },
- {
- name: "IPv6 not resolvable",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr3.AddressWithPrefix.Address,
- expectedErr: &tcpip.ErrTimeout{},
- },
- {
- name: "IPv4 bad local address",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr2.AddressWithPrefix.Address,
- localAddr: utils.Ipv4Addr2.AddressWithPrefix.Address,
- expectedErr: &tcpip.ErrBadLocalAddress{},
- },
- {
- name: "IPv6 bad local address",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr2.AddressWithPrefix.Address,
- localAddr: utils.Ipv6Addr2.AddressWithPrefix.Address,
- expectedErr: &tcpip.ErrBadLocalAddress{},
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- stackOpts := stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
- }
-
- host1Stack, _ := setupStack(t, stackOpts, host1NICID, host2NICID)
-
- ch := make(chan stack.LinkResolutionResult, 1)
- err := host1Stack.GetLinkAddress(host1NICID, test.remoteAddr, test.localAddr, test.netProto, func(r stack.LinkResolutionResult) {
- ch <- r
- })
- if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
- t.Fatalf("got host1Stack.GetLinkAddress(%d, %s, '', %d, _) = %s, want = %s", host1NICID, test.remoteAddr, test.netProto, err, &tcpip.ErrWouldBlock{})
- }
- wantRes := stack.LinkResolutionResult{Err: test.expectedErr}
- if test.expectedErr == nil {
- wantRes.LinkAddress = utils.LinkAddr2
- }
- if diff := cmp.Diff(wantRes, <-ch); diff != "" {
- t.Fatalf("link resolution result mismatch (-want +got):\n%s", diff)
- }
- })
- }
-}
-
-func TestRouteResolvedFields(t *testing.T) {
- const (
- host1NICID = 1
- host2NICID = 4
- )
-
- tests := []struct {
- name string
- netProto tcpip.NetworkProtocolNumber
- localAddr tcpip.Address
- remoteAddr tcpip.Address
- immediatelyResolvable bool
- expectedErr tcpip.Error
- expectedLinkAddr tcpip.LinkAddress
- }{
- {
- name: "IPv4 immediately resolvable",
- netProto: ipv4.ProtocolNumber,
- localAddr: utils.Ipv4Addr1.AddressWithPrefix.Address,
- remoteAddr: header.IPv4AllSystems,
- immediatelyResolvable: true,
- expectedErr: nil,
- expectedLinkAddr: header.EthernetAddressFromMulticastIPv4Address(header.IPv4AllSystems),
- },
- {
- name: "IPv6 immediately resolvable",
- netProto: ipv6.ProtocolNumber,
- localAddr: utils.Ipv6Addr1.AddressWithPrefix.Address,
- remoteAddr: header.IPv6AllNodesMulticastAddress,
- immediatelyResolvable: true,
- expectedErr: nil,
- expectedLinkAddr: header.EthernetAddressFromMulticastIPv6Address(header.IPv6AllNodesMulticastAddress),
- },
- {
- name: "IPv4 resolvable",
- netProto: ipv4.ProtocolNumber,
- localAddr: utils.Ipv4Addr1.AddressWithPrefix.Address,
- remoteAddr: utils.Ipv4Addr2.AddressWithPrefix.Address,
- immediatelyResolvable: false,
- expectedErr: nil,
- expectedLinkAddr: utils.LinkAddr2,
- },
- {
- name: "IPv6 resolvable",
- netProto: ipv6.ProtocolNumber,
- localAddr: utils.Ipv6Addr1.AddressWithPrefix.Address,
- remoteAddr: utils.Ipv6Addr2.AddressWithPrefix.Address,
- immediatelyResolvable: false,
- expectedErr: nil,
- expectedLinkAddr: utils.LinkAddr2,
- },
- {
- name: "IPv4 not resolvable",
- netProto: ipv4.ProtocolNumber,
- localAddr: utils.Ipv4Addr1.AddressWithPrefix.Address,
- remoteAddr: utils.Ipv4Addr3.AddressWithPrefix.Address,
- immediatelyResolvable: false,
- expectedErr: &tcpip.ErrTimeout{},
- },
- {
- name: "IPv6 not resolvable",
- netProto: ipv6.ProtocolNumber,
- localAddr: utils.Ipv6Addr1.AddressWithPrefix.Address,
- remoteAddr: utils.Ipv6Addr3.AddressWithPrefix.Address,
- immediatelyResolvable: false,
- expectedErr: &tcpip.ErrTimeout{},
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- stackOpts := stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
- }
-
- host1Stack, _ := setupStack(t, stackOpts, host1NICID, host2NICID)
- r, err := host1Stack.FindRoute(host1NICID, test.localAddr, test.remoteAddr, test.netProto, false /* multicastLoop */)
- if err != nil {
- t.Fatalf("host1Stack.FindRoute(%d, %s, %s, %d, false): %s", host1NICID, test.localAddr, test.remoteAddr, test.netProto, err)
- }
- defer r.Release()
-
- var wantRouteInfo stack.RouteInfo
- wantRouteInfo.LocalLinkAddress = utils.LinkAddr1
- wantRouteInfo.LocalAddress = test.localAddr
- wantRouteInfo.RemoteAddress = test.remoteAddr
- wantRouteInfo.NetProto = test.netProto
- wantRouteInfo.Loop = stack.PacketOut
- wantRouteInfo.RemoteLinkAddress = test.expectedLinkAddr
-
- ch := make(chan stack.ResolvedFieldsResult, 1)
-
- if !test.immediatelyResolvable {
- wantUnresolvedRouteInfo := wantRouteInfo
- wantUnresolvedRouteInfo.RemoteLinkAddress = ""
-
- err := r.ResolvedFields(func(r stack.ResolvedFieldsResult) {
- ch <- r
- })
- if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
- t.Errorf("got r.ResolvedFields(_) = %s, want = %s", err, &tcpip.ErrWouldBlock{})
- }
- if diff := cmp.Diff(stack.ResolvedFieldsResult{RouteInfo: wantRouteInfo, Err: test.expectedErr}, <-ch, cmp.AllowUnexported(stack.RouteInfo{})); diff != "" {
- t.Errorf("route resolve result mismatch (-want +got):\n%s", diff)
- }
-
- if test.expectedErr != nil {
- return
- }
-
- // At this point the neighbor table should be populated so the route
- // should be immediately resolvable.
- }
-
- if err := r.ResolvedFields(func(r stack.ResolvedFieldsResult) {
- ch <- r
- }); err != nil {
- t.Errorf("r.ResolvedFields(_): %s", err)
- }
- select {
- case routeResolveRes := <-ch:
- if diff := cmp.Diff(stack.ResolvedFieldsResult{RouteInfo: wantRouteInfo, Err: nil}, routeResolveRes, cmp.AllowUnexported(stack.RouteInfo{})); diff != "" {
- t.Errorf("route resolve result from resolved route mismatch (-want +got):\n%s", diff)
- }
- default:
- t.Fatal("expected route to be immediately resolvable")
- }
- })
- }
-}
-
-func TestWritePacketsLinkResolution(t *testing.T) {
- const (
- host1NICID = 1
- host2NICID = 4
- )
-
- tests := []struct {
- name string
- netProto tcpip.NetworkProtocolNumber
- remoteAddr tcpip.Address
- expectedWriteErr tcpip.Error
- }{
- {
- name: "IPv4",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr2.AddressWithPrefix.Address,
- expectedWriteErr: nil,
- },
- {
- name: "IPv6",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr2.AddressWithPrefix.Address,
- expectedWriteErr: nil,
- },
- }
-
- 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, host2Stack := setupStack(t, stackOpts, host1NICID, host2NICID)
-
- var serverWQ waiter.Queue
- serverWE, serverCH := waiter.NewChannelEntry(nil)
- serverWQ.EventRegister(&serverWE, waiter.EventIn)
- serverEP, err := host2Stack.NewEndpoint(udp.ProtocolNumber, test.netProto, &serverWQ)
- if err != nil {
- t.Fatalf("host2Stack.NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.netProto, err)
- }
- defer serverEP.Close()
-
- serverAddr := tcpip.FullAddress{Port: 1234}
- if err := serverEP.Bind(serverAddr); err != nil {
- t.Fatalf("serverEP.Bind(%#v): %s", serverAddr, err)
- }
-
- r, err := host1Stack.FindRoute(host1NICID, "", test.remoteAddr, test.netProto, false /* multicastLoop */)
- if err != nil {
- t.Fatalf("host1Stack.FindRoute(%d, '', %s, %d, false): %s", host1NICID, test.remoteAddr, test.netProto, err)
- }
- defer r.Release()
-
- data := []byte{1, 2}
- var pkts stack.PacketBufferList
- for _, d := range data {
- pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: header.UDPMinimumSize + int(r.MaxHeaderLength()),
- Data: buffer.View([]byte{d}).ToVectorisedView(),
- })
- pkt.TransportProtocolNumber = udp.ProtocolNumber
- length := uint16(pkt.Size())
- udpHdr := header.UDP(pkt.TransportHeader().Push(header.UDPMinimumSize))
- udpHdr.Encode(&header.UDPFields{
- SrcPort: 5555,
- DstPort: serverAddr.Port,
- Length: length,
- })
- xsum := r.PseudoHeaderChecksum(udp.ProtocolNumber, length)
- xsum = header.ChecksumCombine(xsum, pkt.Data().AsRange().Checksum())
- udpHdr.SetChecksum(^udpHdr.CalculateChecksum(xsum))
-
- pkts.PushBack(pkt)
- }
-
- params := stack.NetworkHeaderParams{
- Protocol: udp.ProtocolNumber,
- TTL: 64,
- TOS: stack.DefaultTOS,
- }
-
- if n, err := r.WritePackets(nil /* gso */, pkts, params); err != nil {
- t.Fatalf("r.WritePackets(nil, %#v, _): %s", params, err)
- } else if want := pkts.Len(); want != n {
- t.Fatalf("got r.WritePackets(nil, %#v, _) = %d, want = %d", n, params, want)
- }
-
- var writer bytes.Buffer
- count := 0
- for {
- var rOpts tcpip.ReadOptions
- res, err := serverEP.Read(&writer, rOpts)
- if err != nil {
- if _, ok := err.(*tcpip.ErrWouldBlock); ok {
- // Should not have anymore bytes to read after we read the sent
- // number of bytes.
- if count == len(data) {
- break
- }
-
- <-serverCH
- continue
- }
-
- t.Fatalf("serverEP.Read(_, %#v): %s", rOpts, err)
- }
- count += res.Count
- }
-
- if got, want := host2Stack.Stats().UDP.PacketsReceived.Value(), uint64(len(data)); got != want {
- t.Errorf("got host2Stack.Stats().UDP.PacketsReceived.Value() = %d, want = %d", got, want)
- }
- if diff := cmp.Diff(data, writer.Bytes()); diff != "" {
- t.Errorf("read bytes mismatch (-want +got):\n%s", diff)
- }
- })
- }
-}
-
-type eventType int
-
-const (
- entryAdded eventType = iota
- entryChanged
- entryRemoved
-)
-
-func (t eventType) String() string {
- switch t {
- case entryAdded:
- return "add"
- case entryChanged:
- return "change"
- case entryRemoved:
- return "remove"
- default:
- return fmt.Sprintf("unknown (%d)", t)
- }
-}
-
-type eventInfo struct {
- eventType eventType
- nicID tcpip.NICID
- entry stack.NeighborEntry
-}
-
-func (e eventInfo) String() string {
- return fmt.Sprintf("%s event for NIC #%d, %#v", e.eventType, e.nicID, e.entry)
-}
-
-var _ stack.NUDDispatcher = (*nudDispatcher)(nil)
-
-type nudDispatcher struct {
- c chan eventInfo
-}
-
-func (d *nudDispatcher) OnNeighborAdded(nicID tcpip.NICID, entry stack.NeighborEntry) {
- e := eventInfo{
- eventType: entryAdded,
- nicID: nicID,
- entry: entry,
- }
- d.c <- e
-}
-
-func (d *nudDispatcher) OnNeighborChanged(nicID tcpip.NICID, entry stack.NeighborEntry) {
- e := eventInfo{
- eventType: entryChanged,
- nicID: nicID,
- entry: entry,
- }
- d.c <- e
-}
-
-func (d *nudDispatcher) OnNeighborRemoved(nicID tcpip.NICID, entry stack.NeighborEntry) {
- e := eventInfo{
- eventType: entryRemoved,
- nicID: nicID,
- entry: entry,
- }
- d.c <- e
-}
-
-func (d *nudDispatcher) waitForEvent(want eventInfo) error {
- if diff := cmp.Diff(want, <-d.c, cmp.AllowUnexported(eventInfo{}), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAtNanos")); diff != "" {
- return fmt.Errorf("got invalid event (-want +got):\n%s", diff)
- }
- return nil
-}
-
-// TestTCPConfirmNeighborReachability tests that TCP informs layers beneath it
-// that the neighbor used for a route is reachable.
-func TestTCPConfirmNeighborReachability(t *testing.T) {
- tests := []struct {
- name string
- netProto tcpip.NetworkProtocolNumber
- remoteAddr tcpip.Address
- neighborAddr tcpip.Address
- getEndpoints func(*testing.T, *stack.Stack, *stack.Stack, *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{})
- isHost1Listener bool
- }{
- {
- name: "IPv4 active connection through neighbor",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Host2IPv4Addr.AddressWithPrefix.Address,
- neighborAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
- getEndpoints: func(t *testing.T, host1Stack, _, host2Stack *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{}) {
- var listenerWQ waiter.Queue
- listenerEP, err := host2Stack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &listenerWQ)
- if err != nil {
- t.Fatalf("host2Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv4.ProtocolNumber, err)
- }
-
- var clientWQ waiter.Queue
- clientWE, clientCH := waiter.NewChannelEntry(nil)
- clientWQ.EventRegister(&clientWE, waiter.EventOut)
- clientEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &clientWQ)
- if err != nil {
- listenerEP.Close()
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv4.ProtocolNumber, err)
- }
-
- return listenerEP, clientEP, clientCH
- },
- },
- {
- name: "IPv6 active connection through neighbor",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Host2IPv6Addr.AddressWithPrefix.Address,
- neighborAddr: utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address,
- getEndpoints: func(t *testing.T, host1Stack, _, host2Stack *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{}) {
- var listenerWQ waiter.Queue
- listenerEP, err := host2Stack.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &listenerWQ)
- if err != nil {
- t.Fatalf("host2Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv6.ProtocolNumber, err)
- }
-
- var clientWQ waiter.Queue
- clientWE, clientCH := waiter.NewChannelEntry(nil)
- clientWQ.EventRegister(&clientWE, waiter.EventOut)
- clientEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &clientWQ)
- if err != nil {
- listenerEP.Close()
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv6.ProtocolNumber, err)
- }
-
- return listenerEP, clientEP, clientCH
- },
- },
- {
- name: "IPv4 active connection to neighbor",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
- neighborAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
- getEndpoints: func(t *testing.T, host1Stack, routerStack, _ *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{}) {
- var listenerWQ waiter.Queue
- listenerEP, err := routerStack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &listenerWQ)
- if err != nil {
- t.Fatalf("routerStack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv4.ProtocolNumber, err)
- }
-
- var clientWQ waiter.Queue
- clientWE, clientCH := waiter.NewChannelEntry(nil)
- clientWQ.EventRegister(&clientWE, waiter.EventOut)
- clientEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &clientWQ)
- if err != nil {
- listenerEP.Close()
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv4.ProtocolNumber, err)
- }
-
- return listenerEP, clientEP, clientCH
- },
- },
- {
- name: "IPv6 active connection to neighbor",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address,
- neighborAddr: utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address,
- getEndpoints: func(t *testing.T, host1Stack, routerStack, _ *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{}) {
- var listenerWQ waiter.Queue
- listenerEP, err := routerStack.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &listenerWQ)
- if err != nil {
- t.Fatalf("routerStack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv6.ProtocolNumber, err)
- }
-
- var clientWQ waiter.Queue
- clientWE, clientCH := waiter.NewChannelEntry(nil)
- clientWQ.EventRegister(&clientWE, waiter.EventOut)
- clientEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &clientWQ)
- if err != nil {
- listenerEP.Close()
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv6.ProtocolNumber, err)
- }
-
- return listenerEP, clientEP, clientCH
- },
- },
- {
- name: "IPv4 passive connection to neighbor",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Host1IPv4Addr.AddressWithPrefix.Address,
- neighborAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
- getEndpoints: func(t *testing.T, host1Stack, routerStack, _ *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{}) {
- var listenerWQ waiter.Queue
- listenerEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &listenerWQ)
- if err != nil {
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv4.ProtocolNumber, err)
- }
-
- var clientWQ waiter.Queue
- clientWE, clientCH := waiter.NewChannelEntry(nil)
- clientWQ.EventRegister(&clientWE, waiter.EventOut)
- clientEP, err := routerStack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &clientWQ)
- if err != nil {
- listenerEP.Close()
- t.Fatalf("routerStack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv4.ProtocolNumber, err)
- }
-
- return listenerEP, clientEP, clientCH
- },
- isHost1Listener: true,
- },
- {
- name: "IPv6 passive connection to neighbor",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Host1IPv6Addr.AddressWithPrefix.Address,
- neighborAddr: utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address,
- getEndpoints: func(t *testing.T, host1Stack, routerStack, _ *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{}) {
- var listenerWQ waiter.Queue
- listenerEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &listenerWQ)
- if err != nil {
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv6.ProtocolNumber, err)
- }
-
- var clientWQ waiter.Queue
- clientWE, clientCH := waiter.NewChannelEntry(nil)
- clientWQ.EventRegister(&clientWE, waiter.EventOut)
- clientEP, err := routerStack.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &clientWQ)
- if err != nil {
- listenerEP.Close()
- t.Fatalf("routerStack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv6.ProtocolNumber, err)
- }
-
- return listenerEP, clientEP, clientCH
- },
- isHost1Listener: true,
- },
- {
- name: "IPv4 passive connection through neighbor",
- netProto: ipv4.ProtocolNumber,
- remoteAddr: utils.Host1IPv4Addr.AddressWithPrefix.Address,
- neighborAddr: utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address,
- getEndpoints: func(t *testing.T, host1Stack, _, host2Stack *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{}) {
- var listenerWQ waiter.Queue
- listenerEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &listenerWQ)
- if err != nil {
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv4.ProtocolNumber, err)
- }
-
- var clientWQ waiter.Queue
- clientWE, clientCH := waiter.NewChannelEntry(nil)
- clientWQ.EventRegister(&clientWE, waiter.EventOut)
- clientEP, err := host2Stack.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &clientWQ)
- if err != nil {
- listenerEP.Close()
- t.Fatalf("host2Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv4.ProtocolNumber, err)
- }
-
- return listenerEP, clientEP, clientCH
- },
- isHost1Listener: true,
- },
- {
- name: "IPv6 passive connection through neighbor",
- netProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Host1IPv6Addr.AddressWithPrefix.Address,
- neighborAddr: utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address,
- getEndpoints: func(t *testing.T, host1Stack, _, host2Stack *stack.Stack) (tcpip.Endpoint, tcpip.Endpoint, <-chan struct{}) {
- var listenerWQ waiter.Queue
- listenerEP, err := host1Stack.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &listenerWQ)
- if err != nil {
- t.Fatalf("host1Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv6.ProtocolNumber, err)
- }
-
- var clientWQ waiter.Queue
- clientWE, clientCH := waiter.NewChannelEntry(nil)
- clientWQ.EventRegister(&clientWE, waiter.EventOut)
- clientEP, err := host2Stack.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &clientWQ)
- if err != nil {
- listenerEP.Close()
- t.Fatalf("host2Stack.NewEndpoint(%d, %d, _): %s", tcp.ProtocolNumber, ipv6.ProtocolNumber, err)
- }
-
- return listenerEP, clientEP, clientCH
- },
- isHost1Listener: true,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- clock := faketime.NewManualClock()
- nudDisp := nudDispatcher{
- c: make(chan eventInfo, 3),
- }
- stackOpts := stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
- TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol},
- Clock: clock,
- }
- host1StackOpts := stackOpts
- host1StackOpts.NUDDisp = &nudDisp
-
- host1Stack := stack.New(host1StackOpts)
- routerStack := stack.New(stackOpts)
- host2Stack := stack.New(stackOpts)
- utils.SetupRoutedStacks(t, host1Stack, routerStack, host2Stack)
-
- // Add a reachable dynamic entry to our neighbor table for the remote.
- {
- ch := make(chan stack.LinkResolutionResult, 1)
- err := host1Stack.GetLinkAddress(utils.Host1NICID, test.neighborAddr, "", test.netProto, func(r stack.LinkResolutionResult) {
- ch <- r
- })
- if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
- t.Fatalf("got host1Stack.GetLinkAddress(%d, %s, '', %d, _) = %s, want = %s", utils.Host1NICID, test.neighborAddr, test.netProto, err, &tcpip.ErrWouldBlock{})
- }
- if diff := cmp.Diff(stack.LinkResolutionResult{LinkAddress: utils.LinkAddr2, Err: nil}, <-ch); diff != "" {
- t.Fatalf("link resolution mismatch (-want +got):\n%s", diff)
- }
- }
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryAdded,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Incomplete, Addr: test.neighborAddr},
- }); err != nil {
- t.Fatalf("error waiting for initial NUD event: %s", err)
- }
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryChanged,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Reachable, Addr: test.neighborAddr, LinkAddr: utils.LinkAddr2},
- }); err != nil {
- t.Fatalf("error waiting for reachable NUD event: %s", err)
- }
-
- // Wait for the remote's neighbor entry to be stale before creating a
- // TCP connection from host1 to some remote.
- nudConfigs, err := host1Stack.NUDConfigurations(utils.Host1NICID, test.netProto)
- if err != nil {
- t.Fatalf("host1Stack.NUDConfigurations(%d, %d): %s", utils.Host1NICID, test.netProto, err)
- }
- // The maximum reachable time for a neighbor is some maximum random factor
- // applied to the base reachable time.
- //
- // See NUDConfigurations.BaseReachableTime for more information.
- maxReachableTime := time.Duration(float32(nudConfigs.BaseReachableTime) * nudConfigs.MaxRandomFactor)
- clock.Advance(maxReachableTime)
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryChanged,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Stale, Addr: test.neighborAddr, LinkAddr: utils.LinkAddr2},
- }); err != nil {
- t.Fatalf("error waiting for stale NUD event: %s", err)
- }
-
- listenerEP, clientEP, clientCH := test.getEndpoints(t, host1Stack, routerStack, host2Stack)
- defer listenerEP.Close()
- defer clientEP.Close()
- listenerAddr := tcpip.FullAddress{Addr: test.remoteAddr, 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)
- }
- {
- err := clientEP.Connect(listenerAddr)
- if _, ok := err.(*tcpip.ErrConnectStarted); !ok {
- t.Fatalf("got clientEP.Connect(%#v) = %s, want = %s", listenerAddr, err, &tcpip.ErrConnectStarted{})
- }
- }
-
- // Wait for the TCP handshake to complete then make sure the neighbor is
- // reachable without entering the probe state as TCP should provide NUD
- // with confirmation that the neighbor is reachable (indicated by a
- // successful 3-way handshake).
- <-clientCH
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryChanged,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Delay, Addr: test.neighborAddr, LinkAddr: utils.LinkAddr2},
- }); err != nil {
- t.Fatalf("error waiting for delay NUD event: %s", err)
- }
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryChanged,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Reachable, Addr: test.neighborAddr, LinkAddr: utils.LinkAddr2},
- }); err != nil {
- t.Fatalf("error waiting for reachable NUD event: %s", err)
- }
-
- // Wait for the neighbor to be stale again then send data to the remote.
- //
- // On successful transmission, the neighbor should become reachable
- // without probing the neighbor as a TCP ACK would be received which is an
- // indication of the neighbor being reachable.
- clock.Advance(maxReachableTime)
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryChanged,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Stale, Addr: test.neighborAddr, LinkAddr: utils.LinkAddr2},
- }); err != nil {
- t.Fatalf("error waiting for stale NUD event: %s", err)
- }
- var r bytes.Reader
- r.Reset([]byte{0})
- var wOpts tcpip.WriteOptions
- if _, err := clientEP.Write(&r, wOpts); err != nil {
- t.Errorf("clientEP.Write(_, %#v): %s", wOpts, err)
- }
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryChanged,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Delay, Addr: test.neighborAddr, LinkAddr: utils.LinkAddr2},
- }); err != nil {
- t.Fatalf("error waiting for delay NUD event: %s", err)
- }
- if test.isHost1Listener {
- // If host1 is not the client, host1 does not send any data so TCP
- // has no way to know it is making forward progress. Because of this,
- // TCP should not mark the route reachable and NUD should go through the
- // probe state.
- clock.Advance(nudConfigs.DelayFirstProbeTime)
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryChanged,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Probe, Addr: test.neighborAddr, LinkAddr: utils.LinkAddr2},
- }); err != nil {
- t.Fatalf("error waiting for probe NUD event: %s", err)
- }
- }
- if err := nudDisp.waitForEvent(eventInfo{
- eventType: entryChanged,
- nicID: utils.Host1NICID,
- entry: stack.NeighborEntry{State: stack.Reachable, Addr: test.neighborAddr, LinkAddr: utils.LinkAddr2},
- }); err != nil {
- t.Fatalf("error waiting for reachable NUD event: %s", err)
- }
- })
- }
-}
-
-func TestDAD(t *testing.T) {
- dadConfigs := stack.DADConfigurations{
- DupAddrDetectTransmits: 1,
- RetransmitTimer: time.Second,
- }
-
- tests := []struct {
- name string
- netProto tcpip.NetworkProtocolNumber
- dadNetProto tcpip.NetworkProtocolNumber
- remoteAddr tcpip.Address
- expectedResult stack.DADResult
- }{
- {
- name: "IPv4 own address",
- netProto: ipv4.ProtocolNumber,
- dadNetProto: arp.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr1.AddressWithPrefix.Address,
- expectedResult: &stack.DADSucceeded{},
- },
- {
- name: "IPv6 own address",
- netProto: ipv6.ProtocolNumber,
- dadNetProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr1.AddressWithPrefix.Address,
- expectedResult: &stack.DADSucceeded{},
- },
- {
- name: "IPv4 duplicate address",
- netProto: ipv4.ProtocolNumber,
- dadNetProto: arp.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr2.AddressWithPrefix.Address,
- expectedResult: &stack.DADDupAddrDetected{HolderLinkAddress: utils.LinkAddr2},
- },
- {
- name: "IPv6 duplicate address",
- netProto: ipv6.ProtocolNumber,
- dadNetProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr2.AddressWithPrefix.Address,
- expectedResult: &stack.DADDupAddrDetected{HolderLinkAddress: utils.LinkAddr2},
- },
- {
- name: "IPv4 no duplicate address",
- netProto: ipv4.ProtocolNumber,
- dadNetProto: arp.ProtocolNumber,
- remoteAddr: utils.Ipv4Addr3.AddressWithPrefix.Address,
- expectedResult: &stack.DADSucceeded{},
- },
- {
- name: "IPv6 no duplicate address",
- netProto: ipv6.ProtocolNumber,
- dadNetProto: ipv6.ProtocolNumber,
- remoteAddr: utils.Ipv6Addr3.AddressWithPrefix.Address,
- expectedResult: &stack.DADSucceeded{},
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- clock := faketime.NewManualClock()
- stackOpts := stack.Options{
- Clock: clock,
- NetworkProtocols: []stack.NetworkProtocolFactory{
- arp.NewProtocol,
- ipv4.NewProtocol,
- ipv6.NewProtocol,
- },
- }
-
- host1Stack, _ := setupStack(t, stackOpts, utils.Host1NICID, utils.Host2NICID)
-
- // DAD should be disabled by default.
- if res, err := host1Stack.CheckDuplicateAddress(utils.Host1NICID, test.netProto, test.remoteAddr, func(r stack.DADResult) {
- t.Errorf("unexpectedly called DAD completion handler when DAD was supposed to be disabled")
- }); err != nil {
- t.Fatalf("host1Stack.CheckDuplicateAddress(%d, %d, %s, _): %s", utils.Host1NICID, test.netProto, test.remoteAddr, err)
- } else if res != stack.DADDisabled {
- t.Errorf("got host1Stack.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", utils.Host1NICID, test.netProto, test.remoteAddr, res, stack.DADDisabled)
- }
-
- // Enable DAD then attempt to check if an address is duplicated.
- netEP, err := host1Stack.GetNetworkEndpoint(utils.Host1NICID, test.dadNetProto)
- if err != nil {
- t.Fatalf("host1Stack.GetNetworkEndpoint(%d, %d): %s", utils.Host1NICID, test.dadNetProto, err)
- }
- dad, ok := netEP.(stack.DuplicateAddressDetector)
- if !ok {
- t.Fatalf("expected %T to implement stack.DuplicateAddressDetector", netEP)
- }
- dad.SetDADConfigurations(dadConfigs)
- ch := make(chan stack.DADResult, 3)
- if res, err := host1Stack.CheckDuplicateAddress(utils.Host1NICID, test.netProto, test.remoteAddr, func(r stack.DADResult) {
- ch <- r
- }); err != nil {
- t.Fatalf("host1Stack.CheckDuplicateAddress(%d, %d, %s, _): %s", utils.Host1NICID, test.netProto, test.remoteAddr, err)
- } else if res != stack.DADStarting {
- t.Errorf("got host1Stack.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", utils.Host1NICID, test.netProto, test.remoteAddr, res, stack.DADStarting)
- }
-
- expectResults := 1
- if _, ok := test.expectedResult.(*stack.DADSucceeded); ok {
- const delta = time.Nanosecond
- clock.Advance(time.Duration(dadConfigs.DupAddrDetectTransmits)*dadConfigs.RetransmitTimer - delta)
- select {
- case r := <-ch:
- t.Fatalf("unexpectedly got DAD result before the DAD timeout; r = %#v", r)
- default:
- }
-
- // If we expect the resolve to succeed try requesting DAD again on the
- // same address. The handler for the new request should be called once
- // the original DAD request completes.
- expectResults = 2
- if res, err := host1Stack.CheckDuplicateAddress(utils.Host1NICID, test.netProto, test.remoteAddr, func(r stack.DADResult) {
- ch <- r
- }); err != nil {
- t.Fatalf("host1Stack.CheckDuplicateAddress(%d, %d, %s, _): %s", utils.Host1NICID, test.netProto, test.remoteAddr, err)
- } else if res != stack.DADAlreadyRunning {
- t.Errorf("got host1Stack.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", utils.Host1NICID, test.netProto, test.remoteAddr, res, stack.DADAlreadyRunning)
- }
-
- clock.Advance(delta)
- }
-
- for i := 0; i < expectResults; i++ {
- if diff := cmp.Diff(test.expectedResult, <-ch); diff != "" {
- t.Errorf("(i=%d) DAD result mismatch (-want +got):\n%s", i, diff)
- }
- }
-
- // Should have no more results.
- select {
- case r := <-ch:
- t.Errorf("unexpectedly got an extra DAD result; r = %#v", r)
- default:
- }
- })
- }
-}
diff --git a/pkg/tcpip/tests/integration/loopback_test.go b/pkg/tcpip/tests/integration/loopback_test.go
deleted file mode 100644
index 0a9ea1aa8..000000000
--- a/pkg/tcpip/tests/integration/loopback_test.go
+++ /dev/null
@@ -1,765 +0,0 @@
-// 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 loopback_test
-
-import (
- "bytes"
- "testing"
- "time"
-
- "github.com/google/go-cmp/cmp"
- "gvisor.dev/gvisor/pkg/tcpip"
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
- "gvisor.dev/gvisor/pkg/tcpip/checker"
- "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/tests/utils"
- "gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
- "gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
- "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
- "gvisor.dev/gvisor/pkg/waiter"
-)
-
-var _ ipv6.NDPDispatcher = (*ndpDispatcher)(nil)
-
-type ndpDispatcher struct{}
-
-func (*ndpDispatcher) OnDuplicateAddressDetectionResult(tcpip.NICID, tcpip.Address, stack.DADResult) {
-}
-
-func (*ndpDispatcher) OnDefaultRouterDiscovered(tcpip.NICID, tcpip.Address) bool {
- return false
-}
-
-func (*ndpDispatcher) OnDefaultRouterInvalidated(tcpip.NICID, tcpip.Address) {}
-
-func (*ndpDispatcher) OnOnLinkPrefixDiscovered(tcpip.NICID, tcpip.Subnet) bool {
- return false
-}
-
-func (*ndpDispatcher) OnOnLinkPrefixInvalidated(tcpip.NICID, tcpip.Subnet) {}
-
-func (*ndpDispatcher) OnAutoGenAddress(tcpip.NICID, tcpip.AddressWithPrefix) bool {
- return true
-}
-
-func (*ndpDispatcher) OnAutoGenAddressDeprecated(tcpip.NICID, tcpip.AddressWithPrefix) {}
-
-func (*ndpDispatcher) OnAutoGenAddressInvalidated(tcpip.NICID, tcpip.AddressWithPrefix) {}
-
-func (*ndpDispatcher) OnRecursiveDNSServerOption(tcpip.NICID, []tcpip.Address, time.Duration) {}
-
-func (*ndpDispatcher) OnDNSSearchListOption(tcpip.NICID, []string, time.Duration) {}
-
-func (*ndpDispatcher) OnDHCPv6Configuration(tcpip.NICID, ipv6.DHCPv6ConfigurationFromNDPRA) {}
-
-// TestInitialLoopbackAddresses tests that the loopback interface does not
-// auto-generate a link-local address when it is brought up.
-func TestInitialLoopbackAddresses(t *testing.T) {
- const nicID = 1
-
- s := stack.New(stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocolWithOptions(ipv6.Options{
- NDPDisp: &ndpDispatcher{},
- AutoGenLinkLocal: true,
- OpaqueIIDOpts: ipv6.OpaqueInterfaceIdentifierOptions{
- NICNameFromID: func(nicID tcpip.NICID, nicName string) string {
- t.Fatalf("should not attempt to get name for NIC with ID = %d; nicName = %s", nicID, nicName)
- return ""
- },
- },
- })},
- })
-
- if err := s.CreateNIC(nicID, loopback.New()); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
- }
-
- nicsInfo := s.NICInfo()
- if nicInfo, ok := nicsInfo[nicID]; !ok {
- t.Fatalf("did not find NIC with ID = %d in s.NICInfo() = %#v", nicID, nicsInfo)
- } else if got := len(nicInfo.ProtocolAddresses); got != 0 {
- t.Fatalf("got len(nicInfo.ProtocolAddresses) = %d, want = 0; nicInfo.ProtocolAddresses = %#v", got, nicInfo.ProtocolAddresses)
- }
-}
-
-// TestLoopbackAcceptAllInSubnetUDP tests that a loopback interface considers
-// itself bound to all addresses in the subnet of an assigned address and UDP
-// traffic is sent/received correctly.
-func TestLoopbackAcceptAllInSubnetUDP(t *testing.T) {
- const (
- nicID = 1
- localPort = 80
- )
-
- data := []byte{1, 2, 3, 4}
-
- ipv4ProtocolAddress := tcpip.ProtocolAddress{
- Protocol: header.IPv4ProtocolNumber,
- AddressWithPrefix: utils.Ipv4Addr,
- }
- ipv4Bytes := []byte(ipv4ProtocolAddress.AddressWithPrefix.Address)
- ipv4Bytes[len(ipv4Bytes)-1]++
- otherIPv4Address := tcpip.Address(ipv4Bytes)
-
- ipv6ProtocolAddress := tcpip.ProtocolAddress{
- Protocol: header.IPv6ProtocolNumber,
- AddressWithPrefix: utils.Ipv6Addr,
- }
- ipv6Bytes := []byte(utils.Ipv6Addr.Address)
- ipv6Bytes[len(ipv6Bytes)-1]++
- otherIPv6Address := tcpip.Address(ipv6Bytes)
-
- tests := []struct {
- name string
- addAddress tcpip.ProtocolAddress
- bindAddr tcpip.Address
- dstAddr tcpip.Address
- expectRx bool
- }{
- {
- name: "IPv4 bind to wildcard and send to assigned address",
- addAddress: ipv4ProtocolAddress,
- dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
- expectRx: true,
- },
- {
- name: "IPv4 bind to wildcard and send to other subnet-local address",
- addAddress: ipv4ProtocolAddress,
- dstAddr: otherIPv4Address,
- expectRx: true,
- },
- {
- name: "IPv4 bind to wildcard send to other address",
- addAddress: ipv4ProtocolAddress,
- dstAddr: utils.RemoteIPv4Addr,
- expectRx: false,
- },
- {
- name: "IPv4 bind to other subnet-local address and send to assigned address",
- addAddress: ipv4ProtocolAddress,
- bindAddr: otherIPv4Address,
- dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
- expectRx: false,
- },
- {
- name: "IPv4 bind and send to other subnet-local address",
- addAddress: ipv4ProtocolAddress,
- bindAddr: otherIPv4Address,
- dstAddr: otherIPv4Address,
- expectRx: true,
- },
- {
- name: "IPv4 bind to assigned address and send to other subnet-local address",
- addAddress: ipv4ProtocolAddress,
- bindAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
- dstAddr: otherIPv4Address,
- expectRx: false,
- },
-
- {
- name: "IPv6 bind and send to assigned address",
- addAddress: ipv6ProtocolAddress,
- bindAddr: utils.Ipv6Addr.Address,
- dstAddr: utils.Ipv6Addr.Address,
- expectRx: true,
- },
- {
- name: "IPv6 bind to wildcard and send to other subnet-local address",
- addAddress: ipv6ProtocolAddress,
- dstAddr: otherIPv6Address,
- expectRx: false,
- },
- }
-
- 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{udp.NewProtocol},
- })
- if err := s.CreateNIC(nicID, loopback.New()); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
- }
- if err := s.AddProtocolAddress(nicID, test.addAddress); err != nil {
- t.Fatalf("AddProtocolAddress(%d, %+v): %s", nicID, test.addAddress, err)
- }
- s.SetRouteTable([]tcpip.Route{
- {
- Destination: header.IPv4EmptySubnet,
- NIC: nicID,
- },
- {
- Destination: header.IPv6EmptySubnet,
- NIC: nicID,
- },
- })
-
- 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)
- }
- defer rep.Close()
-
- bindAddr := tcpip.FullAddress{Addr: test.bindAddr, Port: localPort}
- if err := rep.Bind(bindAddr); err != nil {
- t.Fatalf("rep.Bind(%+v): %s", bindAddr, err)
- }
-
- sep, err := s.NewEndpoint(udp.ProtocolNumber, test.addAddress.Protocol, &wq)
- if err != nil {
- t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.addAddress.Protocol, err)
- }
- defer sep.Close()
-
- wopts := tcpip.WriteOptions{
- To: &tcpip.FullAddress{
- Addr: test.dstAddr,
- Port: localPort,
- },
- }
- var r bytes.Reader
- r.Reset(data)
- n, err := sep.Write(&r, 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)
- }
-
- var buf bytes.Buffer
- opts := tcpip.ReadOptions{NeedRemoteAddr: true}
- if res, err := rep.Read(&buf, opts); test.expectRx {
- if err != nil {
- t.Fatalf("rep.Read(_, %#v): %s", opts, err)
- }
- if diff := cmp.Diff(tcpip.ReadResult{
- Count: buf.Len(),
- Total: buf.Len(),
- RemoteAddr: tcpip.FullAddress{
- Addr: test.addAddress.AddressWithPrefix.Address,
- },
- }, res,
- checker.IgnoreCmpPath("ControlMessages", "RemoteAddr.NIC", "RemoteAddr.Port"),
- ); diff != "" {
- t.Errorf("rep.Read: unexpected result (-want +got):\n%s", diff)
- }
- if diff := cmp.Diff(data, buf.Bytes()); diff != "" {
- t.Errorf("got UDP payload mismatch (-want +got):\n%s", diff)
- }
- } else if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
- t.Fatalf("got rep.Read = (%v, %s) [with data %x], want = (_, %s)", res, err, buf.Bytes(), &tcpip.ErrWouldBlock{})
- }
- })
- }
-}
-
-// TestLoopbackSubnetLifetimeBoundToAddr tests that the lifetime of an address
-// in a loopback interface's associated subnet is bound to the permanently bound
-// address.
-func TestLoopbackSubnetLifetimeBoundToAddr(t *testing.T) {
- const nicID = 1
-
- protoAddr := tcpip.ProtocolAddress{
- Protocol: ipv4.ProtocolNumber,
- AddressWithPrefix: utils.Ipv4Addr,
- }
- addrBytes := []byte(utils.Ipv4Addr.Address)
- addrBytes[len(addrBytes)-1]++
- otherAddr := tcpip.Address(addrBytes)
-
- s := stack.New(stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol},
- })
- if err := s.CreateNIC(nicID, loopback.New()); err != nil {
- t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
- }
- if err := s.AddProtocolAddress(nicID, protoAddr); err != nil {
- t.Fatalf("s.AddProtocolAddress(%d, %#v): %s", nicID, protoAddr, err)
- }
- s.SetRouteTable([]tcpip.Route{
- {
- Destination: header.IPv4EmptySubnet,
- NIC: nicID,
- },
- })
-
- r, err := s.FindRoute(nicID, otherAddr, utils.RemoteIPv4Addr, ipv4.ProtocolNumber, false /* multicastLoop */)
- if err != nil {
- t.Fatalf("s.FindRoute(%d, %s, %s, %d, false): %s", nicID, otherAddr, utils.RemoteIPv4Addr, ipv4.ProtocolNumber, err)
- }
- defer r.Release()
-
- params := stack.NetworkHeaderParams{
- Protocol: 111,
- TTL: 64,
- TOS: stack.DefaultTOS,
- }
- data := buffer.View([]byte{1, 2, 3, 4})
- if err := r.WritePacket(nil /* gso */, params, stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: int(r.MaxHeaderLength()),
- Data: data.ToVectorisedView(),
- })); err != nil {
- t.Fatalf("r.WritePacket(nil, %#v, _): %s", params, err)
- }
-
- // Removing the address should make the endpoint invalid.
- if err := s.RemoveAddress(nicID, protoAddr.AddressWithPrefix.Address); err != nil {
- t.Fatalf("s.RemoveAddress(%d, %s): %s", nicID, protoAddr.AddressWithPrefix.Address, err)
- }
- {
- err := r.WritePacket(nil /* gso */, params, stack.NewPacketBuffer(stack.PacketBufferOptions{
- ReserveHeaderBytes: int(r.MaxHeaderLength()),
- Data: data.ToVectorisedView(),
- }))
- if _, ok := err.(*tcpip.ErrInvalidEndpointState); !ok {
- t.Fatalf("got r.WritePacket(nil, %#v, _) = %s, want = %s", params, err, &tcpip.ErrInvalidEndpointState{})
- }
- }
-}
-
-// TestLoopbackAcceptAllInSubnetTCP tests that a loopback interface considers
-// itself bound to all addresses in the subnet of an assigned address and TCP
-// traffic is sent/received correctly.
-func TestLoopbackAcceptAllInSubnetTCP(t *testing.T) {
- const (
- nicID = 1
- localPort = 80
- )
-
- ipv4ProtocolAddress := tcpip.ProtocolAddress{
- Protocol: header.IPv4ProtocolNumber,
- AddressWithPrefix: utils.Ipv4Addr,
- }
- ipv4ProtocolAddress.AddressWithPrefix.PrefixLen = 8
- ipv4Bytes := []byte(ipv4ProtocolAddress.AddressWithPrefix.Address)
- ipv4Bytes[len(ipv4Bytes)-1]++
- otherIPv4Address := tcpip.Address(ipv4Bytes)
-
- ipv6ProtocolAddress := tcpip.ProtocolAddress{
- Protocol: header.IPv6ProtocolNumber,
- AddressWithPrefix: utils.Ipv6Addr,
- }
- ipv6Bytes := []byte(utils.Ipv6Addr.Address)
- ipv6Bytes[len(ipv6Bytes)-1]++
- otherIPv6Address := tcpip.Address(ipv6Bytes)
-
- tests := []struct {
- name string
- addAddress tcpip.ProtocolAddress
- bindAddr tcpip.Address
- dstAddr tcpip.Address
- expectAccept bool
- }{
- {
- name: "IPv4 bind to wildcard and send to assigned address",
- addAddress: ipv4ProtocolAddress,
- dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
- expectAccept: true,
- },
- {
- name: "IPv4 bind to wildcard and send to other subnet-local address",
- addAddress: ipv4ProtocolAddress,
- dstAddr: otherIPv4Address,
- expectAccept: true,
- },
- {
- name: "IPv4 bind to wildcard send to other address",
- addAddress: ipv4ProtocolAddress,
- dstAddr: utils.RemoteIPv4Addr,
- expectAccept: false,
- },
- {
- name: "IPv4 bind to other subnet-local address and send to assigned address",
- addAddress: ipv4ProtocolAddress,
- bindAddr: otherIPv4Address,
- dstAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
- expectAccept: false,
- },
- {
- name: "IPv4 bind and send to other subnet-local address",
- addAddress: ipv4ProtocolAddress,
- bindAddr: otherIPv4Address,
- dstAddr: otherIPv4Address,
- expectAccept: true,
- },
- {
- name: "IPv4 bind to assigned address and send to other subnet-local address",
- addAddress: ipv4ProtocolAddress,
- bindAddr: ipv4ProtocolAddress.AddressWithPrefix.Address,
- dstAddr: otherIPv4Address,
- expectAccept: false,
- },
-
- {
- name: "IPv6 bind and send to assigned address",
- addAddress: ipv6ProtocolAddress,
- bindAddr: utils.Ipv6Addr.Address,
- dstAddr: utils.Ipv6Addr.Address,
- expectAccept: true,
- },
- {
- name: "IPv6 bind to wildcard and send to other subnet-local address",
- addAddress: ipv6ProtocolAddress,
- dstAddr: otherIPv6Address,
- expectAccept: false,
- },
- }
-
- 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{tcp.NewProtocol},
- })
- if err := s.CreateNIC(nicID, loopback.New()); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
- }
- if err := s.AddProtocolAddress(nicID, test.addAddress); err != nil {
- t.Fatalf("AddProtocolAddress(%d, %#v): %s", nicID, test.addAddress, err)
- }
- s.SetRouteTable([]tcpip.Route{
- {
- Destination: header.IPv4EmptySubnet,
- NIC: nicID,
- },
- {
- Destination: header.IPv6EmptySubnet,
- NIC: nicID,
- },
- })
-
- var wq waiter.Queue
- we, ch := waiter.NewChannelEntry(nil)
- wq.EventRegister(&we, waiter.EventIn)
- defer wq.EventUnregister(&we)
- listeningEndpoint, err := s.NewEndpoint(tcp.ProtocolNumber, test.addAddress.Protocol, &wq)
- if err != nil {
- t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.addAddress.Protocol, err)
- }
- defer listeningEndpoint.Close()
-
- bindAddr := tcpip.FullAddress{Addr: test.bindAddr, Port: localPort}
- if err := listeningEndpoint.Bind(bindAddr); err != nil {
- t.Fatalf("listeningEndpoint.Bind(%#v): %s", bindAddr, err)
- }
-
- if err := listeningEndpoint.Listen(1); err != nil {
- t.Fatalf("listeningEndpoint.Listen(1): %s", err)
- }
-
- connectingEndpoint, err := s.NewEndpoint(tcp.ProtocolNumber, test.addAddress.Protocol, &wq)
- if err != nil {
- t.Fatalf("s.NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.addAddress.Protocol, err)
- }
- defer connectingEndpoint.Close()
-
- connectAddr := tcpip.FullAddress{
- Addr: test.dstAddr,
- Port: localPort,
- }
- {
- err := connectingEndpoint.Connect(connectAddr)
- if _, ok := err.(*tcpip.ErrConnectStarted); !ok {
- t.Fatalf("connectingEndpoint.Connect(%#v): %s", connectAddr, err)
- }
- }
-
- if !test.expectAccept {
- _, _, err := listeningEndpoint.Accept(nil)
- if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
- t.Fatalf("got listeningEndpoint.Accept(nil) = %s, want = %s", err, &tcpip.ErrWouldBlock{})
- }
- return
- }
-
- // Wait for the listening endpoint to be "readable". That is, wait for a
- // new connection.
- <-ch
- var addr tcpip.FullAddress
- if _, _, err := listeningEndpoint.Accept(&addr); err != nil {
- t.Fatalf("listeningEndpoint.Accept(nil): %s", err)
- }
- if addr.Addr != test.addAddress.AddressWithPrefix.Address {
- t.Errorf("got addr.Addr = %s, want = %s", addr.Addr, test.addAddress.AddressWithPrefix.Address)
- }
- })
- }
-}
-
-func TestExternalLoopbackTraffic(t *testing.T) {
- const (
- nicID1 = 1
- nicID2 = 2
-
- ipv4Loopback = tcpip.Address("\x7f\x00\x00\x01")
-
- numPackets = 1
- )
-
- loopbackSourcedICMPv4 := func(e *channel.Endpoint) {
- utils.RxICMPv4EchoRequest(e, ipv4Loopback, utils.Ipv4Addr.Address)
- }
-
- loopbackSourcedICMPv6 := func(e *channel.Endpoint) {
- utils.RxICMPv6EchoRequest(e, header.IPv6Loopback, utils.Ipv6Addr.Address)
- }
-
- loopbackDestinedICMPv4 := func(e *channel.Endpoint) {
- utils.RxICMPv4EchoRequest(e, utils.RemoteIPv4Addr, ipv4Loopback)
- }
-
- loopbackDestinedICMPv6 := func(e *channel.Endpoint) {
- utils.RxICMPv6EchoRequest(e, utils.RemoteIPv6Addr, header.IPv6Loopback)
- }
-
- invalidSrcAddrStat := func(s tcpip.IPStats) *tcpip.StatCounter {
- return s.InvalidSourceAddressesReceived
- }
-
- invalidDestAddrStat := func(s tcpip.IPStats) *tcpip.StatCounter {
- return s.InvalidDestinationAddressesReceived
- }
-
- tests := []struct {
- name string
- dropExternalLoopback bool
- forwarding bool
- rxICMP func(*channel.Endpoint)
- invalidAddressStat func(tcpip.IPStats) *tcpip.StatCounter
- shouldAccept bool
- }{
- {
- name: "IPv4 external loopback sourced traffic without forwarding and drop external loopback disabled",
- dropExternalLoopback: false,
- forwarding: false,
- rxICMP: loopbackSourcedICMPv4,
- invalidAddressStat: invalidSrcAddrStat,
- shouldAccept: true,
- },
- {
- name: "IPv4 external loopback sourced traffic without forwarding and drop external loopback enabled",
- dropExternalLoopback: true,
- forwarding: false,
- rxICMP: loopbackSourcedICMPv4,
- invalidAddressStat: invalidSrcAddrStat,
- shouldAccept: false,
- },
- {
- name: "IPv4 external loopback sourced traffic with forwarding and drop external loopback disabled",
- dropExternalLoopback: false,
- forwarding: true,
- rxICMP: loopbackSourcedICMPv4,
- invalidAddressStat: invalidSrcAddrStat,
- shouldAccept: true,
- },
- {
- name: "IPv4 external loopback sourced traffic with forwarding and drop external loopback enabled",
- dropExternalLoopback: true,
- forwarding: true,
- rxICMP: loopbackSourcedICMPv4,
- invalidAddressStat: invalidSrcAddrStat,
- shouldAccept: false,
- },
- {
- name: "IPv4 external loopback destined traffic without forwarding and drop external loopback disabled",
- dropExternalLoopback: false,
- forwarding: false,
- rxICMP: loopbackDestinedICMPv4,
- invalidAddressStat: invalidDestAddrStat,
- shouldAccept: false,
- },
- {
- name: "IPv4 external loopback destined traffic without forwarding and drop external loopback enabled",
- dropExternalLoopback: true,
- forwarding: false,
- rxICMP: loopbackDestinedICMPv4,
- invalidAddressStat: invalidDestAddrStat,
- shouldAccept: false,
- },
- {
- name: "IPv4 external loopback destined traffic with forwarding and drop external loopback disabled",
- dropExternalLoopback: false,
- forwarding: true,
- rxICMP: loopbackDestinedICMPv4,
- invalidAddressStat: invalidDestAddrStat,
- shouldAccept: true,
- },
- {
- name: "IPv4 external loopback destined traffic with forwarding and drop external loopback enabled",
- dropExternalLoopback: true,
- forwarding: true,
- rxICMP: loopbackDestinedICMPv4,
- invalidAddressStat: invalidDestAddrStat,
- shouldAccept: false,
- },
-
- {
- name: "IPv6 external loopback sourced traffic without forwarding and drop external loopback disabled",
- dropExternalLoopback: false,
- forwarding: false,
- rxICMP: loopbackSourcedICMPv6,
- invalidAddressStat: invalidSrcAddrStat,
- shouldAccept: true,
- },
- {
- name: "IPv6 external loopback sourced traffic without forwarding and drop external loopback enabled",
- dropExternalLoopback: true,
- forwarding: false,
- rxICMP: loopbackSourcedICMPv6,
- invalidAddressStat: invalidSrcAddrStat,
- shouldAccept: false,
- },
- {
- name: "IPv6 external loopback sourced traffic with forwarding and drop external loopback disabled",
- dropExternalLoopback: false,
- forwarding: true,
- rxICMP: loopbackSourcedICMPv6,
- invalidAddressStat: invalidSrcAddrStat,
- shouldAccept: true,
- },
- {
- name: "IPv6 external loopback sourced traffic with forwarding and drop external loopback enabled",
- dropExternalLoopback: true,
- forwarding: true,
- rxICMP: loopbackSourcedICMPv6,
- invalidAddressStat: invalidSrcAddrStat,
- shouldAccept: false,
- },
- {
- name: "IPv6 external loopback destined traffic without forwarding and drop external loopback disabled",
- dropExternalLoopback: false,
- forwarding: false,
- rxICMP: loopbackDestinedICMPv6,
- invalidAddressStat: invalidDestAddrStat,
- shouldAccept: false,
- },
- {
- name: "IPv6 external loopback destined traffic without forwarding and drop external loopback enabled",
- dropExternalLoopback: true,
- forwarding: false,
- rxICMP: loopbackDestinedICMPv6,
- invalidAddressStat: invalidDestAddrStat,
- shouldAccept: false,
- },
- {
- name: "IPv6 external loopback destined traffic with forwarding and drop external loopback disabled",
- dropExternalLoopback: false,
- forwarding: true,
- rxICMP: loopbackDestinedICMPv6,
- invalidAddressStat: invalidDestAddrStat,
- shouldAccept: true,
- },
- {
- name: "IPv6 external loopback destined traffic with forwarding and drop external loopback enabled",
- dropExternalLoopback: true,
- forwarding: true,
- rxICMP: loopbackDestinedICMPv6,
- invalidAddressStat: invalidDestAddrStat,
- shouldAccept: false,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- s := stack.New(stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{
- ipv4.NewProtocolWithOptions(ipv4.Options{
- DropExternalLoopbackTraffic: test.dropExternalLoopback,
- }),
- ipv6.NewProtocolWithOptions(ipv6.Options{
- DropExternalLoopbackTraffic: test.dropExternalLoopback,
- }),
- },
- TransportProtocols: []stack.TransportProtocolFactory{icmp.NewProtocol4, icmp.NewProtocol6},
- })
- e := channel.New(1, header.IPv6MinimumMTU, "")
- if err := s.CreateNIC(nicID1, e); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID1, err)
- }
- if err := s.AddAddressWithPrefix(nicID1, ipv4.ProtocolNumber, utils.Ipv4Addr); err != nil {
- t.Fatalf("AddAddressWithPrefix(%d, %d, %s): %s", nicID1, ipv4.ProtocolNumber, utils.Ipv4Addr, err)
- }
- if err := s.AddAddressWithPrefix(nicID1, ipv6.ProtocolNumber, utils.Ipv6Addr); err != nil {
- t.Fatalf("AddAddressWithPrefix(%d, %d, %s): %s", nicID1, ipv6.ProtocolNumber, utils.Ipv6Addr, err)
- }
-
- if err := s.CreateNIC(nicID2, loopback.New()); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID2, err)
- }
- if err := s.AddAddress(nicID2, ipv4.ProtocolNumber, ipv4Loopback); err != nil {
- t.Fatalf("AddAddress(%d, %d, %s): %s", nicID2, ipv4.ProtocolNumber, ipv4Loopback, err)
- }
- if err := s.AddAddress(nicID2, ipv6.ProtocolNumber, header.IPv6Loopback); err != nil {
- t.Fatalf("AddAddress(%d, %d, %s): %s", nicID2, ipv6.ProtocolNumber, header.IPv6Loopback, err)
- }
-
- if test.forwarding {
- if err := s.SetForwarding(ipv4.ProtocolNumber, true); err != nil {
- t.Fatalf("SetForwarding(%d, true): %s", ipv4.ProtocolNumber, err)
- }
- if err := s.SetForwarding(ipv6.ProtocolNumber, true); err != nil {
- t.Fatalf("SetForwarding(%d, true): %s", ipv6.ProtocolNumber, err)
- }
- }
-
- s.SetRouteTable([]tcpip.Route{
- tcpip.Route{
- Destination: header.IPv4EmptySubnet,
- NIC: nicID1,
- },
- tcpip.Route{
- Destination: header.IPv6EmptySubnet,
- NIC: nicID1,
- },
- tcpip.Route{
- Destination: ipv4Loopback.WithPrefix().Subnet(),
- NIC: nicID2,
- },
- tcpip.Route{
- Destination: header.IPv6Loopback.WithPrefix().Subnet(),
- NIC: nicID2,
- },
- })
-
- stats := s.Stats().IP
- invalidAddressStat := test.invalidAddressStat(stats)
- deliveredPacketsStat := stats.PacketsDelivered
- if got := invalidAddressStat.Value(); got != 0 {
- t.Fatalf("got invalidAddressStat.Value() = %d, want = 0", got)
- }
- if got := deliveredPacketsStat.Value(); got != 0 {
- t.Fatalf("got deliveredPacketsStat.Value() = %d, want = 0", got)
- }
- test.rxICMP(e)
- var expectedInvalidPackets uint64
- if !test.shouldAccept {
- expectedInvalidPackets = numPackets
- }
- if got := invalidAddressStat.Value(); got != expectedInvalidPackets {
- t.Fatalf("got invalidAddressStat.Value() = %d, want = %d", got, expectedInvalidPackets)
- }
- if got, want := deliveredPacketsStat.Value(), numPackets-expectedInvalidPackets; got != want {
- t.Fatalf("got deliveredPacketsStat.Value() = %d, want = %d", got, want)
- }
- })
- }
-}
diff --git a/pkg/tcpip/tests/integration/multicast_broadcast_test.go b/pkg/tcpip/tests/integration/multicast_broadcast_test.go
deleted file mode 100644
index 77f4a88ec..000000000
--- a/pkg/tcpip/tests/integration/multicast_broadcast_test.go
+++ /dev/null
@@ -1,719 +0,0 @@
-// 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 multicast_broadcast_test
-
-import (
- "bytes"
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "gvisor.dev/gvisor/pkg/tcpip"
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
- "gvisor.dev/gvisor/pkg/tcpip/checker"
- "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/tests/utils"
- "gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
- "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
- "gvisor.dev/gvisor/pkg/waiter"
-)
-
-const (
- defaultMTU = 1280
- ttl = 255
-)
-
-// TestPingMulticastBroadcast tests that responding to an Echo Request destined
-// to a multicast or broadcast address uses a unicast source address for the
-// reply.
-func TestPingMulticastBroadcast(t *testing.T) {
- const nicID = 1
-
- tests := []struct {
- name string
- protoNum tcpip.NetworkProtocolNumber
- rxICMP func(*channel.Endpoint, tcpip.Address, tcpip.Address)
- srcAddr tcpip.Address
- dstAddr tcpip.Address
- expectedSrc tcpip.Address
- }{
- {
- name: "IPv4 unicast",
- protoNum: header.IPv4ProtocolNumber,
- dstAddr: utils.Ipv4Addr.Address,
- srcAddr: utils.RemoteIPv4Addr,
- rxICMP: utils.RxICMPv4EchoRequest,
- expectedSrc: utils.Ipv4Addr.Address,
- },
- {
- name: "IPv4 directed broadcast",
- protoNum: header.IPv4ProtocolNumber,
- rxICMP: utils.RxICMPv4EchoRequest,
- srcAddr: utils.RemoteIPv4Addr,
- dstAddr: utils.Ipv4SubnetBcast,
- expectedSrc: utils.Ipv4Addr.Address,
- },
- {
- name: "IPv4 broadcast",
- protoNum: header.IPv4ProtocolNumber,
- rxICMP: utils.RxICMPv4EchoRequest,
- srcAddr: utils.RemoteIPv4Addr,
- dstAddr: header.IPv4Broadcast,
- expectedSrc: utils.Ipv4Addr.Address,
- },
- {
- name: "IPv4 all-systems multicast",
- protoNum: header.IPv4ProtocolNumber,
- rxICMP: utils.RxICMPv4EchoRequest,
- srcAddr: utils.RemoteIPv4Addr,
- dstAddr: header.IPv4AllSystems,
- expectedSrc: utils.Ipv4Addr.Address,
- },
- {
- name: "IPv6 unicast",
- protoNum: header.IPv6ProtocolNumber,
- rxICMP: utils.RxICMPv6EchoRequest,
- srcAddr: utils.RemoteIPv6Addr,
- dstAddr: utils.Ipv6Addr.Address,
- expectedSrc: utils.Ipv6Addr.Address,
- },
- {
- name: "IPv6 all-nodes multicast",
- protoNum: header.IPv6ProtocolNumber,
- rxICMP: utils.RxICMPv6EchoRequest,
- srcAddr: utils.RemoteIPv6Addr,
- dstAddr: header.IPv6AllNodesMulticastAddress,
- expectedSrc: utils.Ipv6Addr.Address,
- },
- }
-
- 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},
- })
- // We only expect a single packet in response to our ICMP Echo Request.
- e := channel.New(1, defaultMTU, "")
- if err := s.CreateNIC(nicID, e); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
- }
- ipv4ProtoAddr := tcpip.ProtocolAddress{Protocol: header.IPv4ProtocolNumber, AddressWithPrefix: utils.Ipv4Addr}
- if err := s.AddProtocolAddress(nicID, ipv4ProtoAddr); err != nil {
- t.Fatalf("AddProtocolAddress(%d, %#v): %s", nicID, ipv4ProtoAddr, err)
- }
- ipv6ProtoAddr := tcpip.ProtocolAddress{Protocol: header.IPv6ProtocolNumber, AddressWithPrefix: utils.Ipv6Addr}
- if err := s.AddProtocolAddress(nicID, ipv6ProtoAddr); err != nil {
- t.Fatalf("AddProtocolAddress(%d, %#v): %s", nicID, ipv6ProtoAddr, err)
- }
-
- // Default routes for IPv4 and IPv6 so ICMP can find a route to the remote
- // node when attempting to send the ICMP Echo Reply.
- s.SetRouteTable([]tcpip.Route{
- {
- Destination: header.IPv6EmptySubnet,
- NIC: nicID,
- },
- {
- Destination: header.IPv4EmptySubnet,
- NIC: nicID,
- },
- })
-
- test.rxICMP(e, test.srcAddr, test.dstAddr)
- pkt, ok := e.Read()
- if !ok {
- t.Fatal("expected ICMP response")
- }
-
- if pkt.Route.LocalAddress != test.expectedSrc {
- t.Errorf("got pkt.Route.LocalAddress = %s, want = %s", pkt.Route.LocalAddress, test.expectedSrc)
- }
- // The destination of the response packet should be the source of the
- // original packet.
- if pkt.Route.RemoteAddress != test.srcAddr {
- t.Errorf("got pkt.Route.RemoteAddress = %s, want = %s", pkt.Route.RemoteAddress, test.srcAddr)
- }
-
- src, dst := s.NetworkProtocolInstance(test.protoNum).ParseAddresses(stack.PayloadSince(pkt.Pkt.NetworkHeader()))
- if src != test.expectedSrc {
- t.Errorf("got pkt source = %s, want = %s", src, test.expectedSrc)
- }
- // The destination of the response packet should be the source of the
- // original packet.
- if dst != test.srcAddr {
- t.Errorf("got pkt destination = %s, want = %s", dst, test.srcAddr)
- }
- })
- }
-
-}
-
-func rxIPv4UDP(e *channel.Endpoint, src, dst tcpip.Address, data []byte) {
- payloadLen := header.UDPMinimumSize + len(data)
- totalLen := header.IPv4MinimumSize + payloadLen
- hdr := buffer.NewPrependable(totalLen)
- u := header.UDP(hdr.Prepend(payloadLen))
- u.Encode(&header.UDPFields{
- SrcPort: utils.RemotePort,
- DstPort: utils.LocalPort,
- Length: uint16(payloadLen),
- })
- copy(u.Payload(), data)
- sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(payloadLen))
- sum = header.Checksum(data, sum)
- u.SetChecksum(^u.CalculateChecksum(sum))
-
- ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
- ip.Encode(&header.IPv4Fields{
- TotalLength: uint16(totalLen),
- Protocol: uint8(udp.ProtocolNumber),
- TTL: ttl,
- SrcAddr: src,
- DstAddr: dst,
- })
- ip.SetChecksum(^ip.CalculateChecksum())
-
- e.InjectInbound(header.IPv4ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
- Data: hdr.View().ToVectorisedView(),
- }))
-}
-
-func rxIPv6UDP(e *channel.Endpoint, src, dst tcpip.Address, data []byte) {
- payloadLen := header.UDPMinimumSize + len(data)
- hdr := buffer.NewPrependable(header.IPv6MinimumSize + payloadLen)
- u := header.UDP(hdr.Prepend(payloadLen))
- u.Encode(&header.UDPFields{
- SrcPort: utils.RemotePort,
- DstPort: utils.LocalPort,
- Length: uint16(payloadLen),
- })
- copy(u.Payload(), data)
- sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, src, dst, uint16(payloadLen))
- sum = header.Checksum(data, sum)
- u.SetChecksum(^u.CalculateChecksum(sum))
-
- ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
- ip.Encode(&header.IPv6Fields{
- PayloadLength: uint16(payloadLen),
- TransportProtocol: udp.ProtocolNumber,
- HopLimit: ttl,
- SrcAddr: src,
- DstAddr: dst,
- })
-
- e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
- Data: hdr.View().ToVectorisedView(),
- }))
-}
-
-// TestIncomingMulticastAndBroadcast tests receiving a packet destined to some
-// multicast or broadcast address.
-func TestIncomingMulticastAndBroadcast(t *testing.T) {
- const nicID = 1
-
- data := []byte{1, 2, 3, 4}
-
- tests := []struct {
- name string
- proto tcpip.NetworkProtocolNumber
- remoteAddr tcpip.Address
- localAddr tcpip.AddressWithPrefix
- rxUDP func(*channel.Endpoint, tcpip.Address, tcpip.Address, []byte)
- bindAddr tcpip.Address
- dstAddr tcpip.Address
- expectRx bool
- }{
- {
- name: "IPv4 unicast binding to unicast",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- bindAddr: utils.Ipv4Addr.Address,
- dstAddr: utils.Ipv4Addr.Address,
- expectRx: true,
- },
- {
- name: "IPv4 unicast binding to broadcast",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- bindAddr: header.IPv4Broadcast,
- dstAddr: utils.Ipv4Addr.Address,
- expectRx: false,
- },
- {
- name: "IPv4 unicast binding to wildcard",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- dstAddr: utils.Ipv4Addr.Address,
- expectRx: true,
- },
-
- {
- name: "IPv4 directed broadcast binding to subnet broadcast",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- bindAddr: utils.Ipv4SubnetBcast,
- dstAddr: utils.Ipv4SubnetBcast,
- expectRx: true,
- },
- {
- name: "IPv4 directed broadcast binding to broadcast",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- bindAddr: header.IPv4Broadcast,
- dstAddr: utils.Ipv4SubnetBcast,
- expectRx: false,
- },
- {
- name: "IPv4 directed broadcast binding to wildcard",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- dstAddr: utils.Ipv4SubnetBcast,
- expectRx: true,
- },
-
- {
- name: "IPv4 broadcast binding to broadcast",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- bindAddr: header.IPv4Broadcast,
- dstAddr: header.IPv4Broadcast,
- expectRx: true,
- },
- {
- name: "IPv4 broadcast binding to subnet broadcast",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- bindAddr: utils.Ipv4SubnetBcast,
- dstAddr: header.IPv4Broadcast,
- expectRx: false,
- },
- {
- name: "IPv4 broadcast binding to wildcard",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- dstAddr: utils.Ipv4SubnetBcast,
- expectRx: true,
- },
-
- {
- name: "IPv4 all-systems multicast binding to all-systems multicast",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- bindAddr: header.IPv4AllSystems,
- dstAddr: header.IPv4AllSystems,
- expectRx: true,
- },
- {
- name: "IPv4 all-systems multicast binding to wildcard",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- dstAddr: header.IPv4AllSystems,
- expectRx: true,
- },
- {
- name: "IPv4 all-systems multicast binding to unicast",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- bindAddr: utils.Ipv4Addr.Address,
- dstAddr: header.IPv4AllSystems,
- expectRx: false,
- },
-
- // IPv6 has no notion of a broadcast.
- {
- name: "IPv6 unicast binding to wildcard",
- dstAddr: utils.Ipv6Addr.Address,
- proto: header.IPv6ProtocolNumber,
- remoteAddr: utils.RemoteIPv6Addr,
- localAddr: utils.Ipv6Addr,
- rxUDP: rxIPv6UDP,
- expectRx: true,
- },
- {
- name: "IPv6 broadcast-like address binding to wildcard",
- dstAddr: utils.Ipv6SubnetBcast,
- proto: header.IPv6ProtocolNumber,
- remoteAddr: utils.RemoteIPv6Addr,
- localAddr: utils.Ipv6Addr,
- rxUDP: rxIPv6UDP,
- expectRx: false,
- },
- }
-
- 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{udp.NewProtocol},
- })
- e := channel.New(0, defaultMTU, "")
- if err := s.CreateNIC(nicID, e); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
- }
- protoAddr := tcpip.ProtocolAddress{Protocol: test.proto, AddressWithPrefix: test.localAddr}
- if err := s.AddProtocolAddress(nicID, protoAddr); err != nil {
- t.Fatalf("AddProtocolAddress(%d, %#v): %s", nicID, protoAddr, err)
- }
-
- var wq waiter.Queue
- ep, err := s.NewEndpoint(udp.ProtocolNumber, test.proto, &wq)
- if err != nil {
- t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.proto, err)
- }
- defer ep.Close()
-
- bindAddr := tcpip.FullAddress{Addr: test.bindAddr, Port: utils.LocalPort}
- if err := ep.Bind(bindAddr); err != nil {
- t.Fatalf("ep.Bind(%#v): %s", bindAddr, err)
- }
-
- test.rxUDP(e, test.remoteAddr, test.dstAddr, data)
- var buf bytes.Buffer
- var opts tcpip.ReadOptions
- if res, err := ep.Read(&buf, opts); test.expectRx {
- if err != nil {
- t.Fatalf("ep.Read(_, %#v): %s", opts, err)
- }
- if diff := cmp.Diff(tcpip.ReadResult{
- Count: buf.Len(),
- Total: buf.Len(),
- }, res, checker.IgnoreCmpPath("ControlMessages")); diff != "" {
- t.Errorf("ep.Read: unexpected result (-want +got):\n%s", diff)
- }
- if diff := cmp.Diff(data, buf.Bytes()); diff != "" {
- t.Errorf("got UDP payload mismatch (-want +got):\n%s", diff)
- }
- } else if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
- t.Fatalf("got Read = (%v, %s) [with data %x], want = (_, %s)", res, err, buf.Bytes(), &tcpip.ErrWouldBlock{})
- }
- })
- }
-}
-
-// TestReuseAddrAndBroadcast makes sure broadcast packets are received by all
-// interested endpoints.
-func TestReuseAddrAndBroadcast(t *testing.T) {
- const (
- nicID = 1
- localPort = 9000
- loopbackBroadcast = tcpip.Address("\x7f\xff\xff\xff")
- )
-
- tests := []struct {
- name string
- broadcastAddr tcpip.Address
- }{
- {
- name: "Subnet directed broadcast",
- broadcastAddr: loopbackBroadcast,
- },
- {
- name: "IPv4 broadcast",
- broadcastAddr: header.IPv4Broadcast,
- },
- }
-
- 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{udp.NewProtocol},
- })
- if err := s.CreateNIC(nicID, loopback.New()); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
- }
- protoAddr := tcpip.ProtocolAddress{
- Protocol: header.IPv4ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: "\x7f\x00\x00\x01",
- PrefixLen: 8,
- },
- }
- if err := s.AddProtocolAddress(nicID, protoAddr); err != nil {
- t.Fatalf("AddProtocolAddress(%d, %#v): %s", nicID, protoAddr, err)
- }
-
- s.SetRouteTable([]tcpip.Route{
- {
- // We use the empty subnet instead of just the loopback subnet so we
- // also have a route to the IPv4 Broadcast address.
- Destination: header.IPv4EmptySubnet,
- NIC: nicID,
- },
- })
-
- 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.
- 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)
- }
- defer ep.Close()
-
- ep.SocketOptions().SetReuseAddress(true)
- ep.SocketOptions().SetBroadcast(true)
-
- bindAddr := tcpip.FullAddress{Port: localPort}
- if bindWildcard {
- if err := ep.Bind(bindAddr); err != nil {
- t.Fatalf("eps[%d].Bind(%#v): %s", len(eps), bindAddr, err)
- }
- } else {
- bindAddr.Addr = test.broadcastAddr
- if err := ep.Bind(bindAddr); err != nil {
- t.Fatalf("eps[%d].Bind(%#v): %s", len(eps), bindAddr, err)
- }
- }
-
- eps = append(eps, endpointAndWaiter{ep: ep, ch: ch})
- }
- }
-
- for i, wep := range eps {
- writeOpts := tcpip.WriteOptions{
- To: &tcpip.FullAddress{
- Addr: test.broadcastAddr,
- Port: localPort,
- },
- }
- data := []byte{byte(i), 2, 3, 4}
- var r bytes.Reader
- r.Reset(data)
- if n, err := wep.ep.Write(&r, 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), want = (%d, nil)", i, n, want)
- }
-
- for j, rep := range eps {
- // Wait for the endpoint to become readable.
- <-rep.ch
-
- var buf bytes.Buffer
- result, err := rep.ep.Read(&buf, tcpip.ReadOptions{})
- if err != nil {
- t.Errorf("(eps[%d] write) eps[%d].Read: %s", i, j, err)
- continue
- }
- if diff := cmp.Diff(tcpip.ReadResult{
- Count: buf.Len(),
- Total: buf.Len(),
- }, result, checker.IgnoreCmpPath("ControlMessages")); diff != "" {
- t.Errorf("(eps[%d] write) eps[%d].Read: unexpected result (-want +got):\n%s", i, j, diff)
- }
- if diff := cmp.Diff([]byte(data), buf.Bytes()); diff != "" {
- t.Errorf("(eps[%d] write) got UDP payload from eps[%d] mismatch (-want +got):\n%s", i, j, diff)
- }
- }
- }
- })
- }
-}
-
-func TestUDPAddRemoveMembershipSocketOption(t *testing.T) {
- const (
- nicID = 1
- )
-
- data := []byte{1, 2, 3, 4}
-
- tests := []struct {
- name string
- proto tcpip.NetworkProtocolNumber
- remoteAddr tcpip.Address
- localAddr tcpip.AddressWithPrefix
- rxUDP func(*channel.Endpoint, tcpip.Address, tcpip.Address, []byte)
- multicastAddr tcpip.Address
- }{
- {
- name: "IPv4 unicast binding to unicast",
- multicastAddr: "\xe0\x01\x02\x03",
- proto: header.IPv4ProtocolNumber,
- remoteAddr: utils.RemoteIPv4Addr,
- localAddr: utils.Ipv4Addr,
- rxUDP: rxIPv4UDP,
- },
- {
- name: "IPv6 broadcast-like address binding to wildcard",
- multicastAddr: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04",
- proto: header.IPv6ProtocolNumber,
- remoteAddr: utils.RemoteIPv6Addr,
- localAddr: utils.Ipv6Addr,
- rxUDP: rxIPv6UDP,
- },
- }
-
- subTests := []struct {
- name string
- specifyNICID bool
- specifyNICAddr bool
- }{
- {
- name: "Specify NIC ID and NIC address",
- specifyNICID: true,
- specifyNICAddr: true,
- },
- {
- name: "Don't specify NIC ID or NIC address",
- specifyNICID: false,
- specifyNICAddr: false,
- },
- {
- name: "Specify NIC ID but don't specify NIC address",
- specifyNICID: true,
- specifyNICAddr: false,
- },
- {
- name: "Don't specify NIC ID but specify NIC address",
- specifyNICID: false,
- specifyNICAddr: true,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- for _, subTest := range subTests {
- t.Run(subTest.name, func(t *testing.T) {
- s := stack.New(stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
- TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
- })
- e := channel.New(0, defaultMTU, "")
- if err := s.CreateNIC(nicID, e); err != nil {
- t.Fatalf("CreateNIC(%d, _): %s", nicID, err)
- }
- protoAddr := tcpip.ProtocolAddress{Protocol: test.proto, AddressWithPrefix: test.localAddr}
- if err := s.AddProtocolAddress(nicID, protoAddr); err != nil {
- t.Fatalf("AddProtocolAddress(%d, %#v): %s", nicID, protoAddr, err)
- }
-
- // Set the route table so that UDP can find a NIC that is
- // routable to the multicast address when the NIC isn't specified.
- if !subTest.specifyNICID && !subTest.specifyNICAddr {
- s.SetRouteTable([]tcpip.Route{
- {
- Destination: header.IPv6EmptySubnet,
- NIC: nicID,
- },
- {
- Destination: header.IPv4EmptySubnet,
- NIC: nicID,
- },
- })
- }
-
- var wq waiter.Queue
- ep, err := s.NewEndpoint(udp.ProtocolNumber, test.proto, &wq)
- if err != nil {
- t.Fatalf("NewEndpoint(%d, %d, _): %s", udp.ProtocolNumber, test.proto, err)
- }
- defer ep.Close()
-
- bindAddr := tcpip.FullAddress{Port: utils.LocalPort}
- if err := ep.Bind(bindAddr); err != nil {
- t.Fatalf("ep.Bind(%#v): %s", bindAddr, err)
- }
-
- memOpt := tcpip.MembershipOption{MulticastAddr: test.multicastAddr}
- if subTest.specifyNICID {
- memOpt.NIC = nicID
- }
- if subTest.specifyNICAddr {
- memOpt.InterfaceAddr = test.localAddr.Address
- }
-
- // We should receive UDP packets to the group once we join the
- // multicast group.
- addOpt := tcpip.AddMembershipOption(memOpt)
- if err := ep.SetSockOpt(&addOpt); err != nil {
- t.Fatalf("ep.SetSockOpt(&%#v): %s", addOpt, err)
- }
- test.rxUDP(e, test.remoteAddr, test.multicastAddr, data)
- var buf bytes.Buffer
- result, err := ep.Read(&buf, tcpip.ReadOptions{})
- if err != nil {
- t.Fatalf("ep.Read: %s", err)
- } else {
- if diff := cmp.Diff(tcpip.ReadResult{
- Count: buf.Len(),
- Total: buf.Len(),
- }, result, checker.IgnoreCmpPath("ControlMessages")); diff != "" {
- t.Errorf("ep.Read: unexpected result (-want +got):\n%s", diff)
- }
- if diff := cmp.Diff(data, buf.Bytes()); diff != "" {
- t.Errorf("got UDP payload mismatch (-want +got):\n%s", diff)
- }
- }
-
- // We should not receive UDP packets to the group once we leave
- // the multicast group.
- removeOpt := tcpip.RemoveMembershipOption(memOpt)
- if err := ep.SetSockOpt(&removeOpt); err != nil {
- t.Fatalf("ep.SetSockOpt(&%#v): %s", removeOpt, err)
- }
- {
- _, err := ep.Read(&buf, tcpip.ReadOptions{})
- if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
- t.Fatalf("got ep.Read = (_, %s), want = (_, %s)", err, &tcpip.ErrWouldBlock{})
- }
- }
- })
- }
- })
- }
-}
diff --git a/pkg/tcpip/tests/integration/route_test.go b/pkg/tcpip/tests/integration/route_test.go
deleted file mode 100644
index 568a982bb..000000000
--- a/pkg/tcpip/tests/integration/route_test.go
+++ /dev/null
@@ -1,432 +0,0 @@
-// 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 route_test
-
-import (
- "bytes"
- "fmt"
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "gvisor.dev/gvisor/pkg/tcpip"
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
- "gvisor.dev/gvisor/pkg/tcpip/checker"
- "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/tests/utils"
- "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: utils.Ipv4Addr.Address,
- icmpBuf: ipv4ICMPBuf,
- checkLinkEndpoint: channelEPCheck,
- },
- {
- name: "IPv6 non-loopback",
- transProto: icmp.ProtocolNumber6,
- netProto: ipv6.ProtocolNumber,
- linkEndpoint: channelEP,
- localAddr: utils.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) {
- for _, dropExternalLoopback := range []bool{true, false} {
- t.Run(fmt.Sprintf("DropExternalLoopback=%t", dropExternalLoopback), func(t *testing.T) {
- s := stack.New(stack.Options{
- NetworkProtocols: []stack.NetworkProtocolFactory{
- ipv4.NewProtocolWithOptions(ipv4.Options{
- DropExternalLoopbackTraffic: dropExternalLoopback,
- }),
- ipv6.NewProtocolWithOptions(ipv6.Options{
- DropExternalLoopbackTraffic: dropExternalLoopback,
- }),
- },
- 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
- }
-
- var r bytes.Reader
- payload := test.icmpBuf(t)
- r.Reset(payload)
- var wOpts tcpip.WriteOptions
- if n, err := ep.Write(&r, 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 w bytes.Buffer
- rr, err := ep.Read(&w, tcpip.ReadOptions{
- NeedRemoteAddr: true,
- })
- if err != nil {
- t.Fatalf("ep.Read(...): %s", err)
- }
- if diff := cmp.Diff(buffer.View(w.Bytes()[icmpDataOffset:]), payload[icmpDataOffset:]); diff != "" {
- t.Errorf("received data mismatch (-want +got):\n%s", diff)
- }
- if rr.RemoteAddr.Addr != test.localAddr {
- t.Errorf("got addr.Addr = %s, want = %s", rr.RemoteAddr.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: utils.Ipv4Addr1,
- firstPrimaryAddr: utils.Ipv4Addr2,
- },
- {
- name: "IPv6",
- canBePrimaryAddr: utils.Ipv6Addr1,
- firstPrimaryAddr: utils.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 := []byte{1, 2, 3, 4}
- {
- var r bytes.Reader
- r.Reset(clientPayload)
- wOpts := tcpip.WriteOptions{
- To: &serverAddr,
- }
- if n, err := client.Write(&r, 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
- var readBuf bytes.Buffer
- if read, err := server.Read(&readBuf, tcpip.ReadOptions{NeedRemoteAddr: true}); err != nil {
- t.Fatalf("server.Read(_): %s", err)
- } else {
- clientAddr = read.RemoteAddr
-
- if diff := cmp.Diff(tcpip.ReadResult{
- Count: readBuf.Len(),
- Total: readBuf.Len(),
- RemoteAddr: tcpip.FullAddress{
- Addr: test.canBePrimaryAddr.AddressWithPrefix.Address,
- },
- }, read, checker.IgnoreCmpPath(
- "ControlMessages",
- "RemoteAddr.NIC",
- "RemoteAddr.Port",
- )); diff != "" {
- t.Errorf("server.Read: unexpected result (-want +got):\n%s", diff)
- }
- if diff := cmp.Diff(buffer.View(clientPayload), buffer.View(readBuf.Bytes())); diff != "" {
- t.Errorf("server read clientPayload mismatch (-want +got):\n%s", diff)
- }
- if t.Failed() {
- t.FailNow()
- }
- }
-
- serverPayload := []byte{1, 2, 3, 4}
- {
- var r bytes.Reader
- r.Reset(serverPayload)
- wOpts := tcpip.WriteOptions{
- To: &clientAddr,
- }
- if n, err := server.Write(&r, 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
-
- readBuf.Reset()
- if read, err := client.Read(&readBuf, tcpip.ReadOptions{NeedRemoteAddr: true}); err != nil {
- t.Fatalf("client.Read(_): %s", err)
- } else {
- if diff := cmp.Diff(tcpip.ReadResult{
- Count: readBuf.Len(),
- Total: readBuf.Len(),
- RemoteAddr: tcpip.FullAddress{Addr: serverAddr.Addr},
- }, read, checker.IgnoreCmpPath(
- "ControlMessages",
- "RemoteAddr.NIC",
- "RemoteAddr.Port",
- )); diff != "" {
- t.Errorf("client.Read: unexpected result (-want +got):\n%s", diff)
- }
- if diff := cmp.Diff(buffer.View(serverPayload), buffer.View(readBuf.Bytes())); diff != "" {
- t.Errorf("client read serverPayload mismatch (-want +got):\n%s", diff)
- }
- if t.Failed() {
- t.FailNow()
- }
- }
- })
- }
- })
- }
-}
diff --git a/pkg/tcpip/tests/utils/BUILD b/pkg/tcpip/tests/utils/BUILD
deleted file mode 100644
index a9699a367..000000000
--- a/pkg/tcpip/tests/utils/BUILD
+++ /dev/null
@@ -1,22 +0,0 @@
-load("//tools:defs.bzl", "go_library")
-
-package(licenses = ["notice"])
-
-go_library(
- name = "utils",
- srcs = ["utils.go"],
- visibility = ["//pkg/tcpip/tests:__subpackages__"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/header",
- "//pkg/tcpip/link/channel",
- "//pkg/tcpip/link/ethernet",
- "//pkg/tcpip/link/nested",
- "//pkg/tcpip/link/pipe",
- "//pkg/tcpip/network/ipv4",
- "//pkg/tcpip/network/ipv6",
- "//pkg/tcpip/stack",
- "//pkg/tcpip/transport/icmp",
- ],
-)
diff --git a/pkg/tcpip/tests/utils/utils.go b/pkg/tcpip/tests/utils/utils.go
deleted file mode 100644
index d1c9f3a94..000000000
--- a/pkg/tcpip/tests/utils/utils.go
+++ /dev/null
@@ -1,374 +0,0 @@
-// 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 utils holds common testing utilities for tcpip.
-package utils
-
-import (
- "net"
- "testing"
-
- "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/ethernet"
- "gvisor.dev/gvisor/pkg/tcpip/link/nested"
- "gvisor.dev/gvisor/pkg/tcpip/link/pipe"
- "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"
-)
-
-// Common NIC IDs used by tests.
-const (
- Host1NICID = 1
- RouterNICID1 = 2
- RouterNICID2 = 3
- Host2NICID = 4
-)
-
-// Common link addresses used by tests.
-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")
-)
-
-const (
- ttl = 255
-)
-
-// Common IP addresses used by tests.
-var (
- Ipv4Addr = tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("192.168.1.58").To4()),
- PrefixLen: 24,
- }
- Ipv4Subnet = Ipv4Addr.Subnet()
- Ipv4SubnetBcast = Ipv4Subnet.Broadcast()
-
- Ipv6Addr = tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("200a::1").To16()),
- PrefixLen: 64,
- }
- Ipv6Subnet = Ipv6Addr.Subnet()
- Ipv6SubnetBcast = Ipv6Subnet.Broadcast()
-
- Ipv4Addr1 = tcpip.ProtocolAddress{
- Protocol: ipv4.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("192.168.0.1").To4()),
- PrefixLen: 24,
- },
- }
- Ipv4Addr2 = tcpip.ProtocolAddress{
- Protocol: ipv4.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("192.168.0.2").To4()),
- 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{
- Address: tcpip.Address(net.ParseIP("a::1").To16()),
- PrefixLen: 64,
- },
- }
- Ipv6Addr2 = tcpip.ProtocolAddress{
- Protocol: ipv6.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("a::2").To16()),
- PrefixLen: 64,
- },
- }
- Ipv6Addr3 = tcpip.ProtocolAddress{
- Protocol: ipv6.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("a::3").To16()),
- PrefixLen: 64,
- },
- }
-
- // Remote addrs.
- RemoteIPv4Addr = tcpip.Address(net.ParseIP("10.0.0.1").To4())
- RemoteIPv6Addr = tcpip.Address(net.ParseIP("200b::1").To16())
-)
-
-// Common ports for testing.
-const (
- RemotePort = 5555
- LocalPort = 80
-)
-
-// Common IP addresses used for testing.
-var (
- Host1IPv4Addr = tcpip.ProtocolAddress{
- Protocol: ipv4.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("192.168.0.2").To4()),
- PrefixLen: 24,
- },
- }
- RouterNIC1IPv4Addr = tcpip.ProtocolAddress{
- Protocol: ipv4.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("192.168.0.1").To4()),
- PrefixLen: 24,
- },
- }
- RouterNIC2IPv4Addr = tcpip.ProtocolAddress{
- Protocol: ipv4.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("10.0.0.1").To4()),
- PrefixLen: 8,
- },
- }
- Host2IPv4Addr = tcpip.ProtocolAddress{
- Protocol: ipv4.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("10.0.0.2").To4()),
- PrefixLen: 8,
- },
- }
- Host1IPv6Addr = tcpip.ProtocolAddress{
- Protocol: ipv6.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("a::2").To16()),
- PrefixLen: 64,
- },
- }
- RouterNIC1IPv6Addr = tcpip.ProtocolAddress{
- Protocol: ipv6.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("a::1").To16()),
- PrefixLen: 64,
- },
- }
- RouterNIC2IPv6Addr = tcpip.ProtocolAddress{
- Protocol: ipv6.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("b::1").To16()),
- PrefixLen: 64,
- },
- }
- Host2IPv6Addr = tcpip.ProtocolAddress{
- Protocol: ipv6.ProtocolNumber,
- AddressWithPrefix: tcpip.AddressWithPrefix{
- Address: tcpip.Address(net.ParseIP("b::2").To16()),
- PrefixLen: 64,
- },
- }
-)
-
-// NewEthernetEndpoint returns an ethernet link endpoint that wraps an inner
-// link endpoint and checks the destination link address before delivering
-// network packets to the network dispatcher.
-//
-// See ethernet.Endpoint for more details.
-func NewEthernetEndpoint(ep stack.LinkEndpoint) *EndpointWithDestinationCheck {
- var e EndpointWithDestinationCheck
- e.Endpoint.Init(ethernet.New(ep), &e)
- return &e
-}
-
-// EndpointWithDestinationCheck is a link endpoint that checks the destination
-// link address before delivering network packets to the network dispatcher.
-type EndpointWithDestinationCheck struct {
- nested.Endpoint
-}
-
-var _ stack.NetworkDispatcher = (*EndpointWithDestinationCheck)(nil)
-var _ stack.LinkEndpoint = (*EndpointWithDestinationCheck)(nil)
-
-// DeliverNetworkPacket implements stack.NetworkDispatcher.
-func (e *EndpointWithDestinationCheck) DeliverNetworkPacket(src, dst tcpip.LinkAddress, proto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
- if dst == e.Endpoint.LinkAddress() || dst == header.EthernetBroadcastAddress || header.IsMulticastEthernetAddress(dst) {
- e.Endpoint.DeliverNetworkPacket(src, dst, proto, pkt)
- }
-}
-
-// SetupRoutedStacks creates the NICs, sets forwarding, adds addresses and sets
-// the route tables for the passed stacks.
-func SetupRoutedStacks(t *testing.T, host1Stack, routerStack, host2Stack *stack.Stack) {
- 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,
- },
- })
-}
-
-// RxICMPv4EchoRequest constructs and injects an ICMPv4 echo request packet on
-// the provided endpoint.
-func RxICMPv4EchoRequest(e *channel.Endpoint, src, dst tcpip.Address) {
- totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize
- hdr := buffer.NewPrependable(totalLen)
- pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
- pkt.SetType(header.ICMPv4Echo)
- pkt.SetCode(header.ICMPv4UnusedCode)
- pkt.SetChecksum(0)
- pkt.SetChecksum(^header.Checksum(pkt, 0))
- ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
- ip.Encode(&header.IPv4Fields{
- TotalLength: uint16(totalLen),
- Protocol: uint8(icmp.ProtocolNumber4),
- TTL: ttl,
- SrcAddr: src,
- DstAddr: dst,
- })
- ip.SetChecksum(^ip.CalculateChecksum())
-
- e.InjectInbound(header.IPv4ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
- Data: hdr.View().ToVectorisedView(),
- }))
-}
-
-// RxICMPv6EchoRequest constructs and injects an ICMPv6 echo request packet on
-// the provided endpoint.
-func RxICMPv6EchoRequest(e *channel.Endpoint, src, dst tcpip.Address) {
- totalLen := header.IPv6MinimumSize + header.ICMPv6MinimumSize
- hdr := buffer.NewPrependable(totalLen)
- pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6MinimumSize))
- pkt.SetType(header.ICMPv6EchoRequest)
- pkt.SetCode(header.ICMPv6UnusedCode)
- pkt.SetChecksum(0)
- pkt.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
- Header: pkt,
- Src: src,
- Dst: dst,
- }))
- ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
- ip.Encode(&header.IPv6Fields{
- PayloadLength: header.ICMPv6MinimumSize,
- TransportProtocol: icmp.ProtocolNumber6,
- HopLimit: ttl,
- SrcAddr: src,
- DstAddr: dst,
- })
-
- e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
- Data: hdr.View().ToVectorisedView(),
- }))
-}