Test IPv6 fragment reassembly

A packetimpact test for: "A node must be able to accept a fragmented packet
that, after reassembly, is as large as 1500 octets."

PiperOrigin-RevId: 321210729
This commit is contained in:
Zeling Feng
2020-07-14 12:29:34 -07:00
committed by gVisor bot
parent 1bfb556ccd
commit 221e1da947
6 changed files with 441 additions and 45 deletions
+138 -34
View File
@@ -15,6 +15,7 @@
package testbench
import (
"encoding/binary"
"encoding/hex"
"fmt"
"reflect"
@@ -470,21 +471,11 @@ func (l *IPv6) ToBytes() ([]byte, error) {
if l.NextHeader != nil {
fields.NextHeader = *l.NextHeader
} else {
switch n := l.next().(type) {
case *TCP:
fields.NextHeader = uint8(header.TCPProtocolNumber)
case *UDP:
fields.NextHeader = uint8(header.UDPProtocolNumber)
case *ICMPv6:
fields.NextHeader = uint8(header.ICMPv6ProtocolNumber)
case *IPv6HopByHopOptionsExtHdr:
fields.NextHeader = uint8(header.IPv6HopByHopOptionsExtHdrIdentifier)
case *IPv6DestinationOptionsExtHdr:
fields.NextHeader = uint8(header.IPv6DestinationOptionsExtHdrIdentifier)
default:
// TODO(b/150301488): Support more protocols as needed.
return nil, fmt.Errorf("ToBytes can't deduce the IPv6 header's next protocol: %#v", n)
nh, err := nextHeaderByLayer(l.next())
if err != nil {
return nil, err
}
fields.NextHeader = nh
}
if l.HopLimit != nil {
fields.HopLimit = *l.HopLimit
@@ -514,6 +505,8 @@ func nextIPv6PayloadParser(nextHeader uint8) layerParser {
return parseIPv6HopByHopOptionsExtHdr
case header.IPv6DestinationOptionsExtHdrIdentifier:
return parseIPv6DestinationOptionsExtHdr
case header.IPv6FragmentExtHdrIdentifier:
return parseIPv6FragmentExtHdr
}
return parsePayload
}
@@ -566,14 +559,56 @@ type IPv6DestinationOptionsExtHdr struct {
Options []byte
}
// IPv6FragmentExtHdr can construct and match an IPv6 Fragment Extension Header.
type IPv6FragmentExtHdr struct {
LayerBase
NextHeader *header.IPv6ExtensionHeaderIdentifier
FragmentOffset *uint16
MoreFragments *bool
Identification *uint32
}
// nextHeaderByLayer finds the correct next header protocol value for layer l.
func nextHeaderByLayer(l Layer) (uint8, error) {
if l == nil {
return uint8(header.IPv6NoNextHeaderIdentifier), nil
}
switch l.(type) {
case *TCP:
return uint8(header.TCPProtocolNumber), nil
case *UDP:
return uint8(header.UDPProtocolNumber), nil
case *ICMPv6:
return uint8(header.ICMPv6ProtocolNumber), nil
case *Payload:
return uint8(header.IPv6NoNextHeaderIdentifier), nil
case *IPv6HopByHopOptionsExtHdr:
return uint8(header.IPv6HopByHopOptionsExtHdrIdentifier), nil
case *IPv6DestinationOptionsExtHdr:
return uint8(header.IPv6DestinationOptionsExtHdrIdentifier), nil
case *IPv6FragmentExtHdr:
return uint8(header.IPv6FragmentExtHdrIdentifier), nil
default:
// TODO(b/161005083): Support more protocols as needed.
return 0, fmt.Errorf("failed to deduce the IPv6 header's next protocol: %T", l)
}
}
// ipv6OptionsExtHdrToBytes serializes an options extension header into bytes.
func ipv6OptionsExtHdrToBytes(nextHeader *header.IPv6ExtensionHeaderIdentifier, options []byte) []byte {
func ipv6OptionsExtHdrToBytes(nextHeader *header.IPv6ExtensionHeaderIdentifier, nextLayer Layer, options []byte) ([]byte, error) {
length := len(options) + 2
if length%8 != 0 {
return nil, fmt.Errorf("IPv6 extension headers must be a multiple of 8 octets long, but the length given: %d, options: %s", length, hex.Dump(options))
}
bytes := make([]byte, length)
if nextHeader == nil {
bytes[0] = byte(header.IPv6NoNextHeaderIdentifier)
} else {
if nextHeader != nil {
bytes[0] = byte(*nextHeader)
} else {
nh, err := nextHeaderByLayer(nextLayer)
if err != nil {
return nil, err
}
bytes[0] = nh
}
// ExtHdrLen field is the length of the extension header
// in 8-octet unit, ignoring the first 8 octets.
@@ -581,7 +616,7 @@ func ipv6OptionsExtHdrToBytes(nextHeader *header.IPv6ExtensionHeaderIdentifier,
// https://tools.ietf.org/html/rfc2460#section-4.6
bytes[1] = uint8((length - 8) / 8)
copy(bytes[2:], options)
return bytes
return bytes, nil
}
// IPv6ExtHdrIdent is a helper routine that allocates a new
@@ -591,14 +626,45 @@ func IPv6ExtHdrIdent(id header.IPv6ExtensionHeaderIdentifier) *header.IPv6Extens
return &id
}
// ToBytes implements Layer.ToBytes
// ToBytes implements Layer.ToBytes.
func (l *IPv6HopByHopOptionsExtHdr) ToBytes() ([]byte, error) {
return ipv6OptionsExtHdrToBytes(l.NextHeader, l.Options), nil
return ipv6OptionsExtHdrToBytes(l.NextHeader, l.next(), l.Options)
}
// ToBytes implements Layer.ToBytes
// ToBytes implements Layer.ToBytes.
func (l *IPv6DestinationOptionsExtHdr) ToBytes() ([]byte, error) {
return ipv6OptionsExtHdrToBytes(l.NextHeader, l.Options), nil
return ipv6OptionsExtHdrToBytes(l.NextHeader, l.next(), l.Options)
}
// ToBytes implements Layer.ToBytes.
func (l *IPv6FragmentExtHdr) ToBytes() ([]byte, error) {
var offset, mflag uint16
var ident uint32
bytes := make([]byte, header.IPv6FragmentExtHdrLength)
if l.NextHeader != nil {
bytes[0] = byte(*l.NextHeader)
} else {
nh, err := nextHeaderByLayer(l.next())
if err != nil {
return nil, err
}
bytes[0] = nh
}
bytes[1] = 0 // reserved
if l.MoreFragments != nil && *l.MoreFragments {
mflag = 1
}
if l.FragmentOffset != nil {
offset = *l.FragmentOffset
}
if l.Identification != nil {
ident = *l.Identification
}
offsetAndMflag := offset<<3 | mflag
binary.BigEndian.PutUint16(bytes[2:], offsetAndMflag)
binary.BigEndian.PutUint32(bytes[4:], ident)
return bytes, nil
}
// parseIPv6ExtHdr parses an IPv6 extension header and returns the NextHeader
@@ -631,6 +697,26 @@ func parseIPv6DestinationOptionsExtHdr(b []byte) (Layer, layerParser) {
return &IPv6DestinationOptionsExtHdr{NextHeader: &nextHeader, Options: options}, nextParser
}
// Bool is a helper routine that allocates a new
// bool value to store v and returns a pointer to it.
func Bool(v bool) *bool {
return &v
}
// parseIPv6FragmentExtHdr parses the bytes assuming that they start
// with an IPv6 Fragment Extension Header.
func parseIPv6FragmentExtHdr(b []byte) (Layer, layerParser) {
nextHeader := b[0]
var extHdr header.IPv6FragmentExtHdr
copy(extHdr[:], b[2:])
return &IPv6FragmentExtHdr{
NextHeader: IPv6ExtHdrIdent(header.IPv6ExtensionHeaderIdentifier(nextHeader)),
FragmentOffset: Uint16(extHdr.FragmentOffset()),
MoreFragments: Bool(extHdr.More()),
Identification: Uint32(extHdr.ID()),
}, nextIPv6PayloadParser(nextHeader)
}
func (l *IPv6HopByHopOptionsExtHdr) length() int {
return len(l.Options) + 2
}
@@ -667,13 +753,31 @@ func (l *IPv6DestinationOptionsExtHdr) String() string {
return stringLayer(l)
}
func (*IPv6FragmentExtHdr) length() int {
return header.IPv6FragmentExtHdrLength
}
func (l *IPv6FragmentExtHdr) match(other Layer) bool {
return equalLayer(l, other)
}
// merge overrides the values in l with the values from other but only in fields
// where the value is not nil.
func (l *IPv6FragmentExtHdr) merge(other Layer) error {
return mergeLayer(l, other)
}
func (l *IPv6FragmentExtHdr) String() string {
return stringLayer(l)
}
// ICMPv6 can construct and match an ICMPv6 encapsulation.
type ICMPv6 struct {
LayerBase
Type *header.ICMPv6Type
Code *byte
Checksum *uint16
NDPPayload []byte
Type *header.ICMPv6Type
Code *byte
Checksum *uint16
Payload []byte
}
func (l *ICMPv6) String() string {
@@ -684,7 +788,7 @@ func (l *ICMPv6) String() string {
// ToBytes implements Layer.ToBytes.
func (l *ICMPv6) ToBytes() ([]byte, error) {
b := make([]byte, header.ICMPv6HeaderSize+len(l.NDPPayload))
b := make([]byte, header.ICMPv6HeaderSize+len(l.Payload))
h := header.ICMPv6(b)
if l.Type != nil {
h.SetType(*l.Type)
@@ -692,7 +796,7 @@ func (l *ICMPv6) ToBytes() ([]byte, error) {
if l.Code != nil {
h.SetCode(*l.Code)
}
copy(h.NDPPayload(), l.NDPPayload)
copy(h.NDPPayload(), l.Payload)
if l.Checksum != nil {
h.SetChecksum(*l.Checksum)
} else {
@@ -725,10 +829,10 @@ func Byte(v byte) *byte {
func parseICMPv6(b []byte) (Layer, layerParser) {
h := header.ICMPv6(b)
icmpv6 := ICMPv6{
Type: ICMPv6Type(h.Type()),
Code: Byte(h.Code()),
Checksum: Uint16(h.Checksum()),
NDPPayload: h.NDPPayload(),
Type: ICMPv6Type(h.Type()),
Code: Byte(h.Code()),
Checksum: Uint16(h.Checksum()),
Payload: h.NDPPayload(),
}
return &icmpv6, nil
}
@@ -738,7 +842,7 @@ func (l *ICMPv6) match(other Layer) bool {
}
func (l *ICMPv6) length() int {
return header.ICMPv6HeaderSize + len(l.NDPPayload)
return header.ICMPv6HeaderSize + len(l.Payload)
}
// merge overrides the values in l with the values from other but only in fields
+114 -4
View File
@@ -593,10 +593,107 @@ func TestIPv6ExtHdrOptions(t *testing.T) {
Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00},
},
&ICMPv6{
Type: ICMPv6Type(header.ICMPv6ParamProblem),
Code: Byte(0),
Checksum: Uint16(0x5f98),
NDPPayload: []byte{0x00, 0x00, 0x00, 0x06},
Type: ICMPv6Type(header.ICMPv6ParamProblem),
Code: Byte(0),
Checksum: Uint16(0x5f98),
Payload: []byte{0x00, 0x00, 0x00, 0x06},
},
},
},
{
description: "IPv6/HopByHop/Fragment",
wantBytes: []byte{
// IPv6 Header
0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
// HopByHop Options
0x2c, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00,
// Fragment ExtHdr
0x3b, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x2a,
},
wantLayers: []Layer{
&IPv6{
SrcAddr: Address(tcpip.Address(net.ParseIP("::1"))),
DstAddr: Address(tcpip.Address(net.ParseIP("fe80::dead:beef"))),
},
&IPv6HopByHopOptionsExtHdr{
NextHeader: IPv6ExtHdrIdent(header.IPv6FragmentExtHdrIdentifier),
Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00},
},
&IPv6FragmentExtHdr{
NextHeader: IPv6ExtHdrIdent(header.IPv6NoNextHeaderIdentifier),
FragmentOffset: Uint16(100),
MoreFragments: Bool(false),
Identification: Uint32(42),
},
&Payload{
Bytes: nil,
},
},
},
{
description: "IPv6/DestOpt/Fragment/Payload",
wantBytes: []byte{
// IPv6 Header
0x60, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x3c, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
// Destination Options
0x2c, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00,
// Fragment ExtHdr
0x3b, 0x00, 0x03, 0x21, 0x00, 0x00, 0x00, 0x2a,
// Sample Data
0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61,
},
wantLayers: []Layer{
&IPv6{
SrcAddr: Address(tcpip.Address(net.ParseIP("::1"))),
DstAddr: Address(tcpip.Address(net.ParseIP("fe80::dead:beef"))),
},
&IPv6DestinationOptionsExtHdr{
NextHeader: IPv6ExtHdrIdent(header.IPv6FragmentExtHdrIdentifier),
Options: []byte{0x05, 0x02, 0x00, 0x00, 0x01, 0x00},
},
&IPv6FragmentExtHdr{
NextHeader: IPv6ExtHdrIdent(header.IPv6NoNextHeaderIdentifier),
FragmentOffset: Uint16(100),
MoreFragments: Bool(true),
Identification: Uint32(42),
},
&Payload{
Bytes: []byte("Sample Data"),
},
},
},
{
description: "IPv6/Fragment/Payload",
wantBytes: []byte{
// IPv6 Header
0x60, 0x00, 0x00, 0x00, 0x00, 0x13, 0x2c, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
// Fragment ExtHdr
0x3b, 0x00, 0x03, 0x21, 0x00, 0x00, 0x00, 0x2a,
// Sample Data
0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x61, 0x74, 0x61,
},
wantLayers: []Layer{
&IPv6{
SrcAddr: Address(tcpip.Address(net.ParseIP("::1"))),
DstAddr: Address(tcpip.Address(net.ParseIP("fe80::dead:beef"))),
},
&IPv6FragmentExtHdr{
NextHeader: IPv6ExtHdrIdent(header.IPv6NoNextHeaderIdentifier),
FragmentOffset: Uint16(100),
MoreFragments: Bool(true),
Identification: Uint32(42),
},
&Payload{
Bytes: []byte("Sample Data"),
},
},
},
@@ -606,6 +703,19 @@ func TestIPv6ExtHdrOptions(t *testing.T) {
if !layers.match(tt.wantLayers) {
t.Fatalf("match failed with diff: %s", layers.diff(tt.wantLayers))
}
// Make sure we can generate correct next header values and checksums
for _, layer := range layers {
switch layer := layer.(type) {
case *IPv6HopByHopOptionsExtHdr:
layer.NextHeader = nil
case *IPv6DestinationOptionsExtHdr:
layer.NextHeader = nil
case *IPv6FragmentExtHdr:
layer.NextHeader = nil
case *ICMPv6:
layer.Checksum = nil
}
}
gotBytes, err := layers.ToBytes()
if err != nil {
t.Fatalf("ToBytes() failed on %s: %s", &layers, err)
+14
View File
@@ -254,6 +254,20 @@ packetimpact_go_test(
],
)
packetimpact_go_test(
name = "ipv6_fragment_reassembly",
srcs = ["ipv6_fragment_reassembly_test.go"],
# TODO(b/160919104): Fix netstack then remove the line below.
expect_netstack_failure = True,
deps = [
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/header",
"//test/packetimpact/testbench",
"@org_golang_x_sys//unix:go_default_library",
],
)
packetimpact_go_test(
name = "udp_send_recv_dgram",
srcs = ["udp_send_recv_dgram_test.go"],
@@ -41,8 +41,8 @@ func TestICMPv6ParamProblemTest(t *testing.T) {
NextHeader: testbench.Uint8(254),
}
icmpv6 := testbench.ICMPv6{
Type: testbench.ICMPv6Type(header.ICMPv6EchoRequest),
NDPPayload: []byte("hello world"),
Type: testbench.ICMPv6Type(header.ICMPv6EchoRequest),
Payload: []byte("hello world"),
}
toSend := (*testbench.Connection)(&conn).CreateFrame(testbench.Layers{&ipv6}, &icmpv6)
@@ -62,8 +62,8 @@ func TestICMPv6ParamProblemTest(t *testing.T) {
binary.BigEndian.PutUint32(b, header.IPv6NextHeaderOffset)
expectedPayload = append(b, expectedPayload...)
expectedICMPv6 := testbench.ICMPv6{
Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem),
NDPPayload: expectedPayload,
Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem),
Payload: expectedPayload,
}
paramProblem := testbench.Layers{
@@ -0,0 +1,168 @@
// 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 ipv6_fragment_reassembly_test
import (
"bytes"
"encoding/binary"
"encoding/hex"
"flag"
"net"
"testing"
"time"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/test/packetimpact/testbench"
)
const (
// The payload length for the first fragment we send. This number
// is a multiple of 8 near 750 (half of 1500).
firstPayloadLength = 752
// The ID field for our outgoing fragments.
fragmentID = 1
// A node must be able to accept a fragmented packet that,
// after reassembly, is as large as 1500 octets.
reassemblyCap = 1500
)
func init() {
testbench.RegisterFlags(flag.CommandLine)
}
func TestIPv6FragmentReassembly(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
conn := testbench.NewIPv6Conn(t, testbench.IPv6{}, testbench.IPv6{})
defer conn.Close()
firstPayloadToSend := make([]byte, firstPayloadLength)
for i := range firstPayloadToSend {
firstPayloadToSend[i] = 'A'
}
secondPayloadLength := reassemblyCap - firstPayloadLength - header.ICMPv6EchoMinimumSize
secondPayloadToSend := firstPayloadToSend[:secondPayloadLength]
icmpv6EchoPayload := make([]byte, 4)
binary.BigEndian.PutUint16(icmpv6EchoPayload[0:], 0)
binary.BigEndian.PutUint16(icmpv6EchoPayload[2:], 0)
icmpv6EchoPayload = append(icmpv6EchoPayload, firstPayloadToSend...)
lIP := tcpip.Address(net.ParseIP(testbench.LocalIPv6).To16())
rIP := tcpip.Address(net.ParseIP(testbench.RemoteIPv6).To16())
icmpv6 := testbench.ICMPv6{
Type: testbench.ICMPv6Type(header.ICMPv6EchoRequest),
Code: testbench.Byte(0),
Payload: icmpv6EchoPayload,
}
icmpv6Bytes, err := icmpv6.ToBytes()
if err != nil {
t.Fatalf("failed to serialize ICMPv6: %s", err)
}
cksum := header.ICMPv6Checksum(
header.ICMPv6(icmpv6Bytes),
lIP,
rIP,
buffer.NewVectorisedView(len(secondPayloadToSend), []buffer.View{secondPayloadToSend}),
)
conn.Send(testbench.IPv6{},
&testbench.IPv6FragmentExtHdr{
FragmentOffset: testbench.Uint16(0),
MoreFragments: testbench.Bool(true),
Identification: testbench.Uint32(fragmentID),
},
&testbench.ICMPv6{
Type: testbench.ICMPv6Type(header.ICMPv6EchoRequest),
Code: testbench.Byte(0),
Payload: icmpv6EchoPayload,
Checksum: &cksum,
})
icmpv6ProtoNum := header.IPv6ExtensionHeaderIdentifier(header.ICMPv6ProtocolNumber)
conn.Send(testbench.IPv6{},
&testbench.IPv6FragmentExtHdr{
NextHeader: &icmpv6ProtoNum,
FragmentOffset: testbench.Uint16((firstPayloadLength + header.ICMPv6EchoMinimumSize) / 8),
MoreFragments: testbench.Bool(false),
Identification: testbench.Uint32(fragmentID),
},
&testbench.Payload{
Bytes: secondPayloadToSend,
})
gotEchoReplyFirstPart, err := conn.ExpectFrame(testbench.Layers{
&testbench.Ether{},
&testbench.IPv6{},
&testbench.IPv6FragmentExtHdr{
FragmentOffset: testbench.Uint16(0),
MoreFragments: testbench.Bool(true),
},
&testbench.ICMPv6{
Type: testbench.ICMPv6Type(header.ICMPv6EchoReply),
Code: testbench.Byte(0),
},
}, time.Second)
if err != nil {
t.Fatalf("expected a fragmented ICMPv6 Echo Reply, but got none: %s", err)
}
id := *gotEchoReplyFirstPart[2].(*testbench.IPv6FragmentExtHdr).Identification
gotFirstPayload, err := gotEchoReplyFirstPart[len(gotEchoReplyFirstPart)-1].ToBytes()
if err != nil {
t.Fatalf("failed to serialize ICMPv6: %s", err)
}
icmpPayload := gotFirstPayload[header.ICMPv6EchoMinimumSize:]
receivedLen := len(icmpPayload)
wantSecondPayloadLen := reassemblyCap - header.ICMPv6EchoMinimumSize - receivedLen
wantFirstPayload := make([]byte, receivedLen)
for i := range wantFirstPayload {
wantFirstPayload[i] = 'A'
}
wantSecondPayload := wantFirstPayload[:wantSecondPayloadLen]
if !bytes.Equal(icmpPayload, wantFirstPayload) {
t.Fatalf("received unexpected payload, got: %s, want: %s",
hex.Dump(icmpPayload),
hex.Dump(wantFirstPayload))
}
gotEchoReplySecondPart, err := conn.ExpectFrame(testbench.Layers{
&testbench.Ether{},
&testbench.IPv6{},
&testbench.IPv6FragmentExtHdr{
NextHeader: &icmpv6ProtoNum,
FragmentOffset: testbench.Uint16(uint16((receivedLen + header.ICMPv6EchoMinimumSize) / 8)),
MoreFragments: testbench.Bool(false),
Identification: &id,
},
&testbench.ICMPv6{},
}, time.Second)
if err != nil {
t.Fatalf("expected the rest of ICMPv6 Echo Reply, but got none: %s", err)
}
secondPayload, err := gotEchoReplySecondPart[len(gotEchoReplySecondPart)-1].ToBytes()
if err != nil {
t.Fatalf("failed to serialize ICMPv6 Echo Reply: %s", err)
}
if !bytes.Equal(secondPayload, wantSecondPayload) {
t.Fatalf("received unexpected payload, got: %s, want: %s",
hex.Dump(secondPayload),
hex.Dump(wantSecondPayload))
}
}
@@ -171,9 +171,9 @@ func TestIPv6UnknownOptionAction(t *testing.T) {
&tb.Ether{},
&tb.IPv6{},
&tb.ICMPv6{
Type: tb.ICMPv6Type(header.ICMPv6ParamProblem),
Code: tb.Byte(2),
NDPPayload: icmpv6Payload,
Type: tb.ICMPv6Type(header.ICMPv6ParamProblem),
Code: tb.Byte(2),
Payload: icmpv6Payload,
},
}, time.Second)
if tt.wantICMPv6 && err != nil {