Refactor to hide C from channel.Endpoint.

This is to aid later implementation for /dev/net/tun device.

PiperOrigin-RevId: 291746025
This commit is contained in:
Ting-Yu Wang
2020-01-27 12:31:47 -08:00
committed by gVisor bot
parent d29e59af9f
commit 6b14be4246
8 changed files with 236 additions and 209 deletions
+36 -7
View File
@@ -18,6 +18,8 @@
package channel
import (
"context"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/stack"
@@ -38,25 +40,52 @@ type Endpoint struct {
linkAddr tcpip.LinkAddress
GSO bool
// C is where outbound packets are queued.
C chan PacketInfo
// c is where outbound packets are queued.
c chan PacketInfo
}
// New creates a new channel endpoint.
func New(size int, mtu uint32, linkAddr tcpip.LinkAddress) *Endpoint {
return &Endpoint{
C: make(chan PacketInfo, size),
c: make(chan PacketInfo, size),
mtu: mtu,
linkAddr: linkAddr,
}
}
// Close closes e. Further packet injections will panic. Reads continue to
// succeed until all packets are read.
func (e *Endpoint) Close() {
close(e.c)
}
// Read does non-blocking read for one packet from the outbound packet queue.
func (e *Endpoint) Read() (PacketInfo, bool) {
select {
case pkt := <-e.c:
return pkt, true
default:
return PacketInfo{}, false
}
}
// ReadContext does blocking read for one packet from the outbound packet queue.
// It can be cancelled by ctx, and in this case, it returns false.
func (e *Endpoint) ReadContext(ctx context.Context) (PacketInfo, bool) {
select {
case pkt := <-e.c:
return pkt, true
case <-ctx.Done():
return PacketInfo{}, false
}
}
// Drain removes all outbound packets from the channel and counts them.
func (e *Endpoint) Drain() int {
c := 0
for {
select {
case <-e.C:
case <-e.c:
c++
default:
return c
@@ -125,7 +154,7 @@ func (e *Endpoint) WritePacket(_ *stack.Route, gso *stack.GSO, protocol tcpip.Ne
}
select {
case e.C <- p:
case e.c <- p:
default:
}
@@ -150,7 +179,7 @@ packetLoop:
}
select {
case e.C <- p:
case e.c <- p:
n++
default:
break packetLoop
@@ -169,7 +198,7 @@ func (e *Endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
}
select {
case e.C <- p:
case e.c <- p:
default:
}
+8 -8
View File
@@ -15,6 +15,7 @@
package arp_test
import (
"context"
"strconv"
"testing"
"time"
@@ -83,7 +84,7 @@ func newTestContext(t *testing.T) *testContext {
}
func (c *testContext) cleanup() {
close(c.linkEP.C)
c.linkEP.Close()
}
func TestDirectRequest(t *testing.T) {
@@ -110,7 +111,7 @@ func TestDirectRequest(t *testing.T) {
for i, address := range []tcpip.Address{stackAddr1, stackAddr2} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
inject(address)
pi := <-c.linkEP.C
pi, _ := c.linkEP.ReadContext(context.Background())
if pi.Proto != arp.ProtocolNumber {
t.Fatalf("expected ARP response, got network protocol number %d", pi.Proto)
}
@@ -134,12 +135,11 @@ func TestDirectRequest(t *testing.T) {
}
inject(stackAddrBad)
select {
case pkt := <-c.linkEP.C:
// Sleep tests are gross, but this will only potentially flake
// if there's a bug. If there is no bug this will reliably
// succeed.
ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond)
if pkt, ok := c.linkEP.ReadContext(ctx); ok {
t.Errorf("stackAddrBad: unexpected packet sent, Proto=%v", pkt.Proto)
case <-time.After(100 * time.Millisecond):
// Sleep tests are gross, but this will only potentially flake
// if there's a bug. If there is no bug this will reliably
// succeed.
}
}
+4 -3
View File
@@ -15,6 +15,7 @@
package ipv6
import (
"context"
"reflect"
"strings"
"testing"
@@ -264,8 +265,8 @@ func newTestContext(t *testing.T) *testContext {
}
func (c *testContext) cleanup() {
close(c.linkEP0.C)
close(c.linkEP1.C)
c.linkEP0.Close()
c.linkEP1.Close()
}
type routeArgs struct {
@@ -276,7 +277,7 @@ type routeArgs struct {
func routeICMPv6Packet(t *testing.T, args routeArgs, fn func(*testing.T, header.ICMPv6)) {
t.Helper()
pi := <-args.src.C
pi, _ := args.src.ReadContext(context.Background())
{
views := []buffer.View{pi.Pkt.Header.View(), pi.Pkt.Data.ToView()}
+42 -45
View File
@@ -15,6 +15,7 @@
package stack_test
import (
"context"
"encoding/binary"
"fmt"
"testing"
@@ -405,7 +406,7 @@ func TestDADResolve(t *testing.T) {
// Validate the sent Neighbor Solicitation messages.
for i := uint8(0); i < test.dupAddrDetectTransmits; i++ {
p := <-e.C
p, _ := e.ReadContext(context.Background())
// Make sure its an IPv6 packet.
if p.Proto != header.IPv6ProtocolNumber {
@@ -3285,29 +3286,29 @@ func TestRouterSolicitation(t *testing.T) {
e := channel.New(int(test.maxRtrSolicit), 1280, linkAddr1)
waitForPkt := func(timeout time.Duration) {
t.Helper()
select {
case p := <-e.C:
if p.Proto != header.IPv6ProtocolNumber {
t.Fatalf("got Proto = %d, want = %d", p.Proto, header.IPv6ProtocolNumber)
}
checker.IPv6(t,
p.Pkt.Header.View(),
checker.SrcAddr(header.IPv6Any),
checker.DstAddr(header.IPv6AllRoutersMulticastAddress),
checker.TTL(header.NDPHopLimit),
checker.NDPRS(),
)
case <-time.After(timeout):
ctx, _ := context.WithTimeout(context.Background(), timeout)
p, ok := e.ReadContext(ctx)
if !ok {
t.Fatal("timed out waiting for packet")
return
}
if p.Proto != header.IPv6ProtocolNumber {
t.Fatalf("got Proto = %d, want = %d", p.Proto, header.IPv6ProtocolNumber)
}
checker.IPv6(t,
p.Pkt.Header.View(),
checker.SrcAddr(header.IPv6Any),
checker.DstAddr(header.IPv6AllRoutersMulticastAddress),
checker.TTL(header.NDPHopLimit),
checker.NDPRS(),
)
}
waitForNothing := func(timeout time.Duration) {
t.Helper()
select {
case <-e.C:
ctx, _ := context.WithTimeout(context.Background(), timeout)
if _, ok := e.ReadContext(ctx); ok {
t.Fatal("unexpectedly got a packet")
case <-time.After(timeout):
}
}
s := stack.New(stack.Options{
@@ -3362,20 +3363,21 @@ func TestStopStartSolicitingRouters(t *testing.T) {
e := channel.New(maxRtrSolicitations, 1280, linkAddr1)
waitForPkt := func(timeout time.Duration) {
t.Helper()
select {
case p := <-e.C:
if p.Proto != header.IPv6ProtocolNumber {
t.Fatalf("got Proto = %d, want = %d", p.Proto, header.IPv6ProtocolNumber)
}
checker.IPv6(t, p.Pkt.Header.View(),
checker.SrcAddr(header.IPv6Any),
checker.DstAddr(header.IPv6AllRoutersMulticastAddress),
checker.TTL(header.NDPHopLimit),
checker.NDPRS())
case <-time.After(timeout):
ctx, _ := context.WithTimeout(context.Background(), timeout)
p, ok := e.ReadContext(ctx)
if !ok {
t.Fatal("timed out waiting for packet")
return
}
if p.Proto != header.IPv6ProtocolNumber {
t.Fatalf("got Proto = %d, want = %d", p.Proto, header.IPv6ProtocolNumber)
}
checker.IPv6(t, p.Pkt.Header.View(),
checker.SrcAddr(header.IPv6Any),
checker.DstAddr(header.IPv6AllRoutersMulticastAddress),
checker.TTL(header.NDPHopLimit),
checker.NDPRS())
}
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
@@ -3391,23 +3393,20 @@ func TestStopStartSolicitingRouters(t *testing.T) {
// Enable forwarding which should stop router solicitations.
s.SetForwarding(true)
select {
case <-e.C:
ctx, _ := context.WithTimeout(context.Background(), delay+defaultTimeout)
if _, ok := e.ReadContext(ctx); ok {
// A single RS may have been sent before forwarding was enabled.
select {
case <-e.C:
ctx, _ = context.WithTimeout(context.Background(), interval+defaultTimeout)
if _, ok = e.ReadContext(ctx); ok {
t.Fatal("Should not have sent more than one RS message")
case <-time.After(interval + defaultTimeout):
}
case <-time.After(delay + defaultTimeout):
}
// Enabling forwarding again should do nothing.
s.SetForwarding(true)
select {
case <-e.C:
ctx, _ = context.WithTimeout(context.Background(), delay+defaultTimeout)
if _, ok := e.ReadContext(ctx); ok {
t.Fatal("unexpectedly got a packet after becoming a router")
case <-time.After(delay + defaultTimeout):
}
// Disable forwarding which should start router solicitations.
@@ -3415,17 +3414,15 @@ func TestStopStartSolicitingRouters(t *testing.T) {
waitForPkt(delay + defaultAsyncEventTimeout)
waitForPkt(interval + defaultAsyncEventTimeout)
waitForPkt(interval + defaultAsyncEventTimeout)
select {
case <-e.C:
ctx, _ = context.WithTimeout(context.Background(), interval+defaultTimeout)
if _, ok := e.ReadContext(ctx); ok {
t.Fatal("unexpectedly got an extra packet after sending out the expected RSs")
case <-time.After(interval + defaultTimeout):
}
// Disabling forwarding again should do nothing.
s.SetForwarding(false)
select {
case <-e.C:
ctx, _ = context.WithTimeout(context.Background(), delay+defaultTimeout)
if _, ok := e.ReadContext(ctx); ok {
t.Fatal("unexpectedly got a packet after becoming a router")
case <-time.After(delay + defaultTimeout):
}
}
+1 -3
View File
@@ -1880,9 +1880,7 @@ func TestNICForwarding(t *testing.T) {
Data: buf.ToVectorisedView(),
})
select {
case <-ep2.C:
default:
if _, ok := ep2.Read(); !ok {
t.Fatal("Packet not forwarded")
}
+2 -4
View File
@@ -623,10 +623,8 @@ func TestTransportForwarding(t *testing.T) {
t.Fatalf("Write failed: %v", err)
}
var p channel.PacketInfo
select {
case p = <-ep2.C:
default:
p, ok := ep2.Read()
if !ok {
t.Fatal("Response packet not forwarded")
}
@@ -18,6 +18,7 @@ package context
import (
"bytes"
"context"
"testing"
"time"
@@ -215,11 +216,9 @@ func (c *Context) Stack() *stack.Stack {
func (c *Context) CheckNoPacketTimeout(errMsg string, wait time.Duration) {
c.t.Helper()
select {
case <-c.linkEP.C:
ctx, _ := context.WithTimeout(context.Background(), wait)
if _, ok := c.linkEP.ReadContext(ctx); ok {
c.t.Fatal(errMsg)
case <-time.After(wait):
}
}
@@ -234,27 +233,27 @@ func (c *Context) CheckNoPacket(errMsg string) {
// 2 seconds.
func (c *Context) GetPacket() []byte {
c.t.Helper()
select {
case p := <-c.linkEP.C:
if p.Proto != ipv4.ProtocolNumber {
c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber)
}
hdr := p.Pkt.Header.View()
b := append(hdr[:len(hdr):len(hdr)], p.Pkt.Data.ToView()...)
if p.GSO != nil && p.GSO.L3HdrLen != header.IPv4MinimumSize {
c.t.Errorf("L3HdrLen %v (expected %v)", p.GSO.L3HdrLen, header.IPv4MinimumSize)
}
checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr))
return b
case <-time.After(2 * time.Second):
ctx, _ := context.WithTimeout(context.Background(), 2*time.Second)
p, ok := c.linkEP.ReadContext(ctx)
if !ok {
c.t.Fatalf("Packet wasn't written out")
return nil
}
return nil
if p.Proto != ipv4.ProtocolNumber {
c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber)
}
hdr := p.Pkt.Header.View()
b := append(hdr[:len(hdr):len(hdr)], p.Pkt.Data.ToView()...)
if p.GSO != nil && p.GSO.L3HdrLen != header.IPv4MinimumSize {
c.t.Errorf("L3HdrLen %v (expected %v)", p.GSO.L3HdrLen, header.IPv4MinimumSize)
}
checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr))
return b
}
// GetPacketNonBlocking reads a packet from the link layer endpoint
@@ -263,20 +262,21 @@ func (c *Context) GetPacket() []byte {
// nil immediately.
func (c *Context) GetPacketNonBlocking() []byte {
c.t.Helper()
select {
case p := <-c.linkEP.C:
if p.Proto != ipv4.ProtocolNumber {
c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber)
}
hdr := p.Pkt.Header.View()
b := append(hdr[:len(hdr):len(hdr)], p.Pkt.Data.ToView()...)
checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr))
return b
default:
p, ok := c.linkEP.Read()
if !ok {
return nil
}
if p.Proto != ipv4.ProtocolNumber {
c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber)
}
hdr := p.Pkt.Header.View()
b := append(hdr[:len(hdr):len(hdr)], p.Pkt.Data.ToView()...)
checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr))
return b
}
// SendICMPPacket builds and sends an ICMPv4 packet via the link layer endpoint.
@@ -484,23 +484,23 @@ func (c *Context) CreateV6Endpoint(v6only bool) {
// and asserts that it is an IPv6 Packet with the expected src/dest addresses.
func (c *Context) GetV6Packet() []byte {
c.t.Helper()
select {
case p := <-c.linkEP.C:
if p.Proto != ipv6.ProtocolNumber {
c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv6.ProtocolNumber)
}
b := make([]byte, p.Pkt.Header.UsedLength()+p.Pkt.Data.Size())
copy(b, p.Pkt.Header.View())
copy(b[p.Pkt.Header.UsedLength():], p.Pkt.Data.ToView())
checker.IPv6(c.t, b, checker.SrcAddr(StackV6Addr), checker.DstAddr(TestV6Addr))
return b
case <-time.After(2 * time.Second):
ctx, _ := context.WithTimeout(context.Background(), 2*time.Second)
p, ok := c.linkEP.ReadContext(ctx)
if !ok {
c.t.Fatalf("Packet wasn't written out")
return nil
}
return nil
if p.Proto != ipv6.ProtocolNumber {
c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv6.ProtocolNumber)
}
b := make([]byte, p.Pkt.Header.UsedLength()+p.Pkt.Data.Size())
copy(b, p.Pkt.Header.View())
copy(b[p.Pkt.Header.UsedLength():], p.Pkt.Data.ToView())
checker.IPv6(c.t, b, checker.SrcAddr(StackV6Addr), checker.DstAddr(TestV6Addr))
return b
}
// SendV6Packet builds and sends an IPv6 Packet via the link layer endpoint of
+98 -94
View File
@@ -16,6 +16,7 @@ package udp_test
import (
"bytes"
"context"
"fmt"
"math/rand"
"testing"
@@ -357,30 +358,29 @@ func (c *testContext) createEndpointForFlow(flow testFlow) {
func (c *testContext) getPacketAndVerify(flow testFlow, checkers ...checker.NetworkChecker) []byte {
c.t.Helper()
select {
case p := <-c.linkEP.C:
if p.Proto != flow.netProto() {
c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, flow.netProto())
}
hdr := p.Pkt.Header.View()
b := append(hdr[:len(hdr):len(hdr)], p.Pkt.Data.ToView()...)
h := flow.header4Tuple(outgoing)
checkers := append(
checkers,
checker.SrcAddr(h.srcAddr.Addr),
checker.DstAddr(h.dstAddr.Addr),
checker.UDP(checker.DstPort(h.dstAddr.Port)),
)
flow.checkerFn()(c.t, b, checkers...)
return b
case <-time.After(2 * time.Second):
ctx, _ := context.WithTimeout(context.Background(), 2*time.Second)
p, ok := c.linkEP.ReadContext(ctx)
if !ok {
c.t.Fatalf("Packet wasn't written out")
return nil
}
return nil
if p.Proto != flow.netProto() {
c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, flow.netProto())
}
hdr := p.Pkt.Header.View()
b := append(hdr[:len(hdr):len(hdr)], p.Pkt.Data.ToView()...)
h := flow.header4Tuple(outgoing)
checkers = append(
checkers,
checker.SrcAddr(h.srcAddr.Addr),
checker.DstAddr(h.dstAddr.Addr),
checker.UDP(checker.DstPort(h.dstAddr.Port)),
)
flow.checkerFn()(c.t, b, checkers...)
return b
}
// injectPacket creates a packet of the given flow and with the given payload,
@@ -1541,48 +1541,50 @@ func TestV4UnknownDestination(t *testing.T) {
}
c.injectPacket(tc.flow, payload)
if !tc.icmpRequired {
select {
case p := <-c.linkEP.C:
ctx, _ := context.WithTimeout(context.Background(), time.Second)
if p, ok := c.linkEP.ReadContext(ctx); ok {
t.Fatalf("unexpected packet received: %+v", p)
case <-time.After(1 * time.Second):
return
}
return
}
select {
case p := <-c.linkEP.C:
var pkt []byte
pkt = append(pkt, p.Pkt.Header.View()...)
pkt = append(pkt, p.Pkt.Data.ToView()...)
if got, want := len(pkt), header.IPv4MinimumProcessableDatagramSize; got > want {
t.Fatalf("got an ICMP packet of size: %d, want: sz <= %d", got, want)
}
hdr := header.IPv4(pkt)
checker.IPv4(t, hdr, checker.ICMPv4(
checker.ICMPv4Type(header.ICMPv4DstUnreachable),
checker.ICMPv4Code(header.ICMPv4PortUnreachable)))
icmpPkt := header.ICMPv4(hdr.Payload())
payloadIPHeader := header.IPv4(icmpPkt.Payload())
wantLen := len(payload)
if tc.largePayload {
wantLen = header.IPv4MinimumProcessableDatagramSize - header.IPv4MinimumSize*2 - header.ICMPv4MinimumSize - header.UDPMinimumSize
}
// In case of large payloads the IP packet may be truncated. Update
// the length field before retrieving the udp datagram payload.
payloadIPHeader.SetTotalLength(uint16(wantLen + header.UDPMinimumSize + header.IPv4MinimumSize))
origDgram := header.UDP(payloadIPHeader.Payload())
if got, want := len(origDgram.Payload()), wantLen; got != want {
t.Fatalf("unexpected payload length got: %d, want: %d", got, want)
}
if got, want := origDgram.Payload(), payload[:wantLen]; !bytes.Equal(got, want) {
t.Fatalf("unexpected payload got: %d, want: %d", got, want)
}
case <-time.After(1 * time.Second):
// ICMP required.
ctx, _ := context.WithTimeout(context.Background(), time.Second)
p, ok := c.linkEP.ReadContext(ctx)
if !ok {
t.Fatalf("packet wasn't written out")
return
}
var pkt []byte
pkt = append(pkt, p.Pkt.Header.View()...)
pkt = append(pkt, p.Pkt.Data.ToView()...)
if got, want := len(pkt), header.IPv4MinimumProcessableDatagramSize; got > want {
t.Fatalf("got an ICMP packet of size: %d, want: sz <= %d", got, want)
}
hdr := header.IPv4(pkt)
checker.IPv4(t, hdr, checker.ICMPv4(
checker.ICMPv4Type(header.ICMPv4DstUnreachable),
checker.ICMPv4Code(header.ICMPv4PortUnreachable)))
icmpPkt := header.ICMPv4(hdr.Payload())
payloadIPHeader := header.IPv4(icmpPkt.Payload())
wantLen := len(payload)
if tc.largePayload {
wantLen = header.IPv4MinimumProcessableDatagramSize - header.IPv4MinimumSize*2 - header.ICMPv4MinimumSize - header.UDPMinimumSize
}
// In case of large payloads the IP packet may be truncated. Update
// the length field before retrieving the udp datagram payload.
payloadIPHeader.SetTotalLength(uint16(wantLen + header.UDPMinimumSize + header.IPv4MinimumSize))
origDgram := header.UDP(payloadIPHeader.Payload())
if got, want := len(origDgram.Payload()), wantLen; got != want {
t.Fatalf("unexpected payload length got: %d, want: %d", got, want)
}
if got, want := origDgram.Payload(), payload[:wantLen]; !bytes.Equal(got, want) {
t.Fatalf("unexpected payload got: %d, want: %d", got, want)
}
})
}
@@ -1615,47 +1617,49 @@ func TestV6UnknownDestination(t *testing.T) {
}
c.injectPacket(tc.flow, payload)
if !tc.icmpRequired {
select {
case p := <-c.linkEP.C:
ctx, _ := context.WithTimeout(context.Background(), time.Second)
if p, ok := c.linkEP.ReadContext(ctx); ok {
t.Fatalf("unexpected packet received: %+v", p)
case <-time.After(1 * time.Second):
return
}
return
}
select {
case p := <-c.linkEP.C:
var pkt []byte
pkt = append(pkt, p.Pkt.Header.View()...)
pkt = append(pkt, p.Pkt.Data.ToView()...)
if got, want := len(pkt), header.IPv6MinimumMTU; got > want {
t.Fatalf("got an ICMP packet of size: %d, want: sz <= %d", got, want)
}
hdr := header.IPv6(pkt)
checker.IPv6(t, hdr, checker.ICMPv6(
checker.ICMPv6Type(header.ICMPv6DstUnreachable),
checker.ICMPv6Code(header.ICMPv6PortUnreachable)))
icmpPkt := header.ICMPv6(hdr.Payload())
payloadIPHeader := header.IPv6(icmpPkt.Payload())
wantLen := len(payload)
if tc.largePayload {
wantLen = header.IPv6MinimumMTU - header.IPv6MinimumSize*2 - header.ICMPv6MinimumSize - header.UDPMinimumSize
}
// In case of large payloads the IP packet may be truncated. Update
// the length field before retrieving the udp datagram payload.
payloadIPHeader.SetPayloadLength(uint16(wantLen + header.UDPMinimumSize))
origDgram := header.UDP(payloadIPHeader.Payload())
if got, want := len(origDgram.Payload()), wantLen; got != want {
t.Fatalf("unexpected payload length got: %d, want: %d", got, want)
}
if got, want := origDgram.Payload(), payload[:wantLen]; !bytes.Equal(got, want) {
t.Fatalf("unexpected payload got: %v, want: %v", got, want)
}
case <-time.After(1 * time.Second):
// ICMP required.
ctx, _ := context.WithTimeout(context.Background(), time.Second)
p, ok := c.linkEP.ReadContext(ctx)
if !ok {
t.Fatalf("packet wasn't written out")
return
}
var pkt []byte
pkt = append(pkt, p.Pkt.Header.View()...)
pkt = append(pkt, p.Pkt.Data.ToView()...)
if got, want := len(pkt), header.IPv6MinimumMTU; got > want {
t.Fatalf("got an ICMP packet of size: %d, want: sz <= %d", got, want)
}
hdr := header.IPv6(pkt)
checker.IPv6(t, hdr, checker.ICMPv6(
checker.ICMPv6Type(header.ICMPv6DstUnreachable),
checker.ICMPv6Code(header.ICMPv6PortUnreachable)))
icmpPkt := header.ICMPv6(hdr.Payload())
payloadIPHeader := header.IPv6(icmpPkt.Payload())
wantLen := len(payload)
if tc.largePayload {
wantLen = header.IPv6MinimumMTU - header.IPv6MinimumSize*2 - header.ICMPv6MinimumSize - header.UDPMinimumSize
}
// In case of large payloads the IP packet may be truncated. Update
// the length field before retrieving the udp datagram payload.
payloadIPHeader.SetPayloadLength(uint16(wantLen + header.UDPMinimumSize))
origDgram := header.UDP(payloadIPHeader.Payload())
if got, want := len(origDgram.Payload()), wantLen; got != want {
t.Fatalf("unexpected payload length got: %d, want: %d", got, want)
}
if got, want := origDgram.Payload(), payload[:wantLen]; !bytes.Equal(got, want) {
t.Fatalf("unexpected payload got: %v, want: %v", got, want)
}
})
}