mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add underflow check when calculating the MTU
Also enforce the minimum MTU for IPv4 and IPv6, and discard packets if the minimum is not met. PiperOrigin-RevId: 338404225
This commit is contained in:
@@ -148,6 +148,13 @@ const (
|
||||
// packet that every IPv4 capable host must be able to
|
||||
// process/reassemble.
|
||||
IPv4MinimumProcessableDatagramSize = 576
|
||||
|
||||
// IPv4MinimumMTU is the minimum MTU required by IPv4, per RFC 791,
|
||||
// section 3.2:
|
||||
// Every internet module must be able to forward a datagram of 68 octets
|
||||
// without further fragmentation. This is because an internet header may be
|
||||
// up to 60 octets, and the minimum fragment is 8 octets.
|
||||
IPv4MinimumMTU = 68
|
||||
)
|
||||
|
||||
// Flags that may be set in an IPv4 packet.
|
||||
|
||||
@@ -101,8 +101,10 @@ const (
|
||||
// The address is ff02::2.
|
||||
IPv6AllRoutersMulticastAddress tcpip.Address = "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
|
||||
|
||||
// IPv6MinimumMTU is the minimum MTU required by IPv6, per RFC 2460,
|
||||
// section 5.
|
||||
// IPv6MinimumMTU is the minimum MTU required by IPv6, per RFC 8200,
|
||||
// section 5:
|
||||
// IPv6 requires that every link in the Internet have an MTU of 1280 octets
|
||||
// or greater. This is known as the IPv6 minimum link MTU.
|
||||
IPv6MinimumMTU = 1280
|
||||
|
||||
// IPv6Loopback is the IPv6 Loopback address.
|
||||
|
||||
@@ -244,25 +244,25 @@ func (f *Fragmentation) releaseReassemblersLocked() {
|
||||
|
||||
// PacketFragmenter is the book-keeping struct for packet fragmentation.
|
||||
type PacketFragmenter struct {
|
||||
transportHeader buffer.View
|
||||
data buffer.VectorisedView
|
||||
reserve int
|
||||
innerMTU int
|
||||
fragmentCount int
|
||||
currentFragment int
|
||||
fragmentOffset int
|
||||
transportHeader buffer.View
|
||||
data buffer.VectorisedView
|
||||
reserve int
|
||||
fragmentPayloadLen int
|
||||
fragmentCount int
|
||||
currentFragment int
|
||||
fragmentOffset int
|
||||
}
|
||||
|
||||
// MakePacketFragmenter prepares the struct needed for packet fragmentation.
|
||||
//
|
||||
// pkt is the packet to be fragmented.
|
||||
//
|
||||
// innerMTU is the maximum number of bytes of fragmentable data a fragment can
|
||||
// fragmentPayloadLen is the maximum number of bytes of fragmentable data a fragment can
|
||||
// have.
|
||||
//
|
||||
// reserve is the number of bytes that should be reserved for the headers in
|
||||
// each generated fragment.
|
||||
func MakePacketFragmenter(pkt *stack.PacketBuffer, innerMTU int, reserve int) PacketFragmenter {
|
||||
func MakePacketFragmenter(pkt *stack.PacketBuffer, fragmentPayloadLen uint32, reserve int) PacketFragmenter {
|
||||
// As per RFC 8200 Section 4.5, some IPv6 extension headers should not be
|
||||
// repeated in each fragment. However we do not currently support any header
|
||||
// of that kind yet, so the following computation is valid for both IPv4 and
|
||||
@@ -273,13 +273,13 @@ func MakePacketFragmenter(pkt *stack.PacketBuffer, innerMTU int, reserve int) Pa
|
||||
var fragmentableData buffer.VectorisedView
|
||||
fragmentableData.AppendView(pkt.TransportHeader().View())
|
||||
fragmentableData.Append(pkt.Data)
|
||||
fragmentCount := (fragmentableData.Size() + innerMTU - 1) / innerMTU
|
||||
fragmentCount := (uint32(fragmentableData.Size()) + fragmentPayloadLen - 1) / fragmentPayloadLen
|
||||
|
||||
return PacketFragmenter{
|
||||
data: fragmentableData,
|
||||
reserve: reserve,
|
||||
innerMTU: innerMTU,
|
||||
fragmentCount: fragmentCount,
|
||||
data: fragmentableData,
|
||||
reserve: reserve,
|
||||
fragmentPayloadLen: int(fragmentPayloadLen),
|
||||
fragmentCount: int(fragmentCount),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ func (pf *PacketFragmenter) BuildNextFragment() (*stack.PacketBuffer, int, int,
|
||||
})
|
||||
|
||||
// Copy data for the fragment.
|
||||
copied := pf.data.ReadToVV(&fragPkt.Data, pf.innerMTU)
|
||||
copied := pf.data.ReadToVV(&fragPkt.Data, pf.fragmentPayloadLen)
|
||||
|
||||
offset := pf.fragmentOffset
|
||||
pf.fragmentOffset += copied
|
||||
|
||||
@@ -403,14 +403,14 @@ func TestPacketFragmenter(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
innerMTU int
|
||||
fragmentPayloadLen uint32
|
||||
transportHeaderLen int
|
||||
payloadSize int
|
||||
wantFragments []fragmentInfo
|
||||
}{
|
||||
{
|
||||
name: "Packet exactly fits in MTU",
|
||||
innerMTU: 1280,
|
||||
fragmentPayloadLen: 1280,
|
||||
transportHeaderLen: 0,
|
||||
payloadSize: 1280,
|
||||
wantFragments: []fragmentInfo{
|
||||
@@ -419,7 +419,7 @@ func TestPacketFragmenter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Packet exactly does not fit in MTU",
|
||||
innerMTU: 1000,
|
||||
fragmentPayloadLen: 1000,
|
||||
transportHeaderLen: 0,
|
||||
payloadSize: 1001,
|
||||
wantFragments: []fragmentInfo{
|
||||
@@ -429,7 +429,7 @@ func TestPacketFragmenter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Packet has a transport header",
|
||||
innerMTU: 560,
|
||||
fragmentPayloadLen: 560,
|
||||
transportHeaderLen: 40,
|
||||
payloadSize: 560,
|
||||
wantFragments: []fragmentInfo{
|
||||
@@ -439,7 +439,7 @@ func TestPacketFragmenter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Packet has a huge transport header",
|
||||
innerMTU: 500,
|
||||
fragmentPayloadLen: 500,
|
||||
transportHeaderLen: 1300,
|
||||
payloadSize: 500,
|
||||
wantFragments: []fragmentInfo{
|
||||
@@ -458,7 +458,7 @@ func TestPacketFragmenter(t *testing.T) {
|
||||
originalPayload.AppendView(pkt.TransportHeader().View())
|
||||
originalPayload.Append(pkt.Data)
|
||||
var reassembledPayload buffer.VectorisedView
|
||||
pf := MakePacketFragmenter(pkt, test.innerMTU, reserve)
|
||||
pf := MakePacketFragmenter(pkt, test.fragmentPayloadLen, reserve)
|
||||
for i := 0; ; i++ {
|
||||
fragPkt, offset, copied, more := pf.BuildNextFragment()
|
||||
wantFragment := test.wantFragments[i]
|
||||
@@ -474,8 +474,8 @@ func TestPacketFragmenter(t *testing.T) {
|
||||
if more != wantFragment.more {
|
||||
t.Errorf("(fragment #%d) got more = %t, want = %t", i, more, wantFragment.more)
|
||||
}
|
||||
if got := fragPkt.Size(); got > test.innerMTU {
|
||||
t.Errorf("(fragment #%d) got fragPkt.Size() = %d, want <= %d", i, got, test.innerMTU)
|
||||
if got := uint32(fragPkt.Size()); got > test.fragmentPayloadLen {
|
||||
t.Errorf("(fragment #%d) got fragPkt.Size() = %d, want <= %d", i, got, test.fragmentPayloadLen)
|
||||
}
|
||||
if got := fragPkt.AvailableHeaderBytes(); got != reserve {
|
||||
t.Errorf("(fragment #%d) got fragPkt.AvailableHeaderBytes() = %d, want = %d", i, got, reserve)
|
||||
|
||||
@@ -182,8 +182,11 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
e.handleControl(stack.ControlPortUnreachable, 0, pkt)
|
||||
|
||||
case header.ICMPv4FragmentationNeeded:
|
||||
mtu := uint32(h.MTU())
|
||||
e.handleControl(stack.ControlPacketTooBig, calculateMTU(mtu), pkt)
|
||||
networkMTU, err := calculateNetworkMTU(uint32(h.MTU()), header.IPv4MinimumSize)
|
||||
if err != nil {
|
||||
networkMTU = 0
|
||||
}
|
||||
e.handleControl(stack.ControlPacketTooBig, networkMTU, pkt)
|
||||
}
|
||||
|
||||
case header.ICMPv4SrcQuench:
|
||||
|
||||
@@ -176,7 +176,11 @@ func (e *endpoint) DefaultTTL() uint8 {
|
||||
// MTU implements stack.NetworkEndpoint.MTU. It returns the link-layer MTU minus
|
||||
// the network layer max header length.
|
||||
func (e *endpoint) MTU() uint32 {
|
||||
return calculateMTU(e.nic.MTU())
|
||||
networkMTU, err := calculateNetworkMTU(e.nic.MTU(), header.IPv4MinimumSize)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return networkMTU
|
||||
}
|
||||
|
||||
// MaxHeaderLength returns the maximum length needed by ipv4 headers (and
|
||||
@@ -211,18 +215,15 @@ func (e *endpoint) addIPHeader(r *stack.Route, pkt *stack.PacketBuffer, params s
|
||||
pkt.NetworkProtocolNumber = ProtocolNumber
|
||||
}
|
||||
|
||||
func (e *endpoint) packetMustBeFragmented(pkt *stack.PacketBuffer, gso *stack.GSO) bool {
|
||||
return (gso == nil || gso.Type == stack.GSONone) && pkt.Size() > int(e.nic.MTU())
|
||||
}
|
||||
|
||||
// handleFragments fragments pkt and calls the handler function on each
|
||||
// fragment. It returns the number of fragments handled and the number of
|
||||
// fragments left to be processed. The IP header must already be present in the
|
||||
// original packet. The mtu is the maximum size of the packets.
|
||||
func (e *endpoint) handleFragments(r *stack.Route, gso *stack.GSO, mtu uint32, pkt *stack.PacketBuffer, handler func(*stack.PacketBuffer) *tcpip.Error) (int, int, *tcpip.Error) {
|
||||
fragMTU := int(calculateFragmentInnerMTU(mtu, pkt))
|
||||
// original packet.
|
||||
func (e *endpoint) handleFragments(r *stack.Route, gso *stack.GSO, networkMTU uint32, pkt *stack.PacketBuffer, handler func(*stack.PacketBuffer) *tcpip.Error) (int, int, *tcpip.Error) {
|
||||
// Round the MTU down to align to 8 bytes.
|
||||
fragmentPayloadSize := networkMTU &^ 7
|
||||
networkHeader := header.IPv4(pkt.NetworkHeader().View())
|
||||
pf := fragmentation.MakePacketFragmenter(pkt, fragMTU, pkt.AvailableHeaderBytes()+len(networkHeader))
|
||||
pf := fragmentation.MakePacketFragmenter(pkt, fragmentPayloadSize, pkt.AvailableHeaderBytes()+len(networkHeader))
|
||||
|
||||
var n int
|
||||
for {
|
||||
@@ -280,8 +281,14 @@ func (e *endpoint) writePacket(r *stack.Route, gso *stack.GSO, pkt *stack.Packet
|
||||
return nil
|
||||
}
|
||||
|
||||
if e.packetMustBeFragmented(pkt, gso) {
|
||||
sent, remain, err := e.handleFragments(r, gso, e.nic.MTU(), pkt, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
networkMTU, err := calculateNetworkMTU(e.nic.MTU(), uint32(pkt.NetworkHeader().View().Size()))
|
||||
if err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
return err
|
||||
}
|
||||
|
||||
if packetMustBeFragmented(pkt, networkMTU, gso) {
|
||||
sent, remain, err := e.handleFragments(r, gso, networkMTU, pkt, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
// TODO(gvisor.dev/issue/3884): Evaluate whether we want to send each
|
||||
// fragment one by one using WritePacket() (current strategy) or if we
|
||||
// want to create a PacketBufferList from the fragments and feed it to
|
||||
@@ -292,6 +299,7 @@ func (e *endpoint) writePacket(r *stack.Route, gso *stack.GSO, pkt *stack.Packet
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(remain))
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.nic.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
return err
|
||||
@@ -311,17 +319,23 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
|
||||
for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
|
||||
e.addIPHeader(r, pkt, params)
|
||||
if e.packetMustBeFragmented(pkt, gso) {
|
||||
networkMTU, err := calculateNetworkMTU(e.nic.MTU(), uint32(pkt.NetworkHeader().View().Size()))
|
||||
if err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(pkts.Len()))
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if packetMustBeFragmented(pkt, networkMTU, gso) {
|
||||
// Keep track of the packet that is about to be fragmented so it can be
|
||||
// removed once the fragmentation is done.
|
||||
originalPkt := pkt
|
||||
if _, _, err := e.handleFragments(r, gso, e.nic.MTU(), pkt, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
if _, _, err := e.handleFragments(r, gso, networkMTU, pkt, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
// Modify the packet list in place with the new fragments.
|
||||
pkts.InsertAfter(pkt, fragPkt)
|
||||
pkt = fragPkt
|
||||
return nil
|
||||
}); err != nil {
|
||||
panic(fmt.Sprintf("e.handleFragments(_, _, %d, _, _) = %s", e.nic.MTU(), err))
|
||||
panic(fmt.Sprintf("e.handleFragments(_, _, %d, _, _) = %s", networkMTU, err))
|
||||
}
|
||||
// Remove the packet that was just fragmented and process the rest.
|
||||
pkts.Remove(originalPkt)
|
||||
@@ -778,26 +792,32 @@ func (p *protocol) SetForwarding(v bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// calculateMTU calculates the network-layer payload MTU based on the link-layer
|
||||
// payload mtu.
|
||||
func calculateMTU(mtu uint32) uint32 {
|
||||
if mtu > MaxTotalSize {
|
||||
mtu = MaxTotalSize
|
||||
// calculateNetworkMTU calculates the network-layer payload MTU based on the
|
||||
// link-layer payload mtu.
|
||||
func calculateNetworkMTU(linkMTU, networkHeaderSize uint32) (uint32, *tcpip.Error) {
|
||||
if linkMTU < header.IPv4MinimumMTU {
|
||||
return 0, tcpip.ErrInvalidEndpointState
|
||||
}
|
||||
return mtu - header.IPv4MinimumSize
|
||||
|
||||
// As per RFC 791 section 3.1, an IPv4 header cannot exceed 60 bytes in
|
||||
// length:
|
||||
// The maximal internet header is 60 octets, and a typical internet header
|
||||
// is 20 octets, allowing a margin for headers of higher level protocols.
|
||||
if networkHeaderSize > header.IPv4MaximumHeaderSize {
|
||||
return 0, tcpip.ErrMalformedHeader
|
||||
}
|
||||
|
||||
networkMTU := linkMTU
|
||||
if networkMTU > MaxTotalSize {
|
||||
networkMTU = MaxTotalSize
|
||||
}
|
||||
|
||||
return networkMTU - uint32(networkHeaderSize), nil
|
||||
}
|
||||
|
||||
// calculateFragmentInnerMTU calculates the maximum number of bytes of
|
||||
// fragmentable data a fragment can have, based on the link layer mtu and pkt's
|
||||
// network header size.
|
||||
func calculateFragmentInnerMTU(mtu uint32, pkt *stack.PacketBuffer) uint32 {
|
||||
if mtu > MaxTotalSize {
|
||||
mtu = MaxTotalSize
|
||||
}
|
||||
mtu -= uint32(pkt.NetworkHeader().View().Size())
|
||||
// Round the MTU down to align to 8 bytes.
|
||||
mtu &^= 7
|
||||
return mtu
|
||||
func packetMustBeFragmented(pkt *stack.PacketBuffer, networkMTU uint32, gso *stack.GSO) bool {
|
||||
payload := pkt.TransportHeader().View().Size() + pkt.Data.Size()
|
||||
return (gso == nil || gso.Type == stack.GSONone) && uint32(payload) > networkMTU
|
||||
}
|
||||
|
||||
// addressToUint32 translates an IPv4 address into its little endian uint32
|
||||
|
||||
@@ -39,7 +39,10 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
const extraHeaderReserve = 50
|
||||
const (
|
||||
extraHeaderReserve = 50
|
||||
defaultMTU = 65536
|
||||
)
|
||||
|
||||
func TestExcludeBroadcast(t *testing.T) {
|
||||
s := stack.New(stack.Options{
|
||||
@@ -47,7 +50,6 @@ func TestExcludeBroadcast(t *testing.T) {
|
||||
TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
|
||||
})
|
||||
|
||||
const defaultMTU = 65536
|
||||
ep := stack.LinkEndpoint(channel.New(256, defaultMTU, ""))
|
||||
if testing.Verbose() {
|
||||
ep = sniffer.New(ep)
|
||||
@@ -103,7 +105,6 @@ func TestExcludeBroadcast(t *testing.T) {
|
||||
// checks the response.
|
||||
func TestIPv4Sanity(t *testing.T) {
|
||||
const (
|
||||
defaultMTU = header.IPv6MinimumMTU
|
||||
ttl = 255
|
||||
nicID = 1
|
||||
randomSequence = 123
|
||||
@@ -132,13 +133,13 @@ func TestIPv4Sanity(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
TTL: ttl,
|
||||
},
|
||||
{
|
||||
name: "bad header checksum",
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
TTL: ttl,
|
||||
badHeaderChecksum: true,
|
||||
@@ -157,35 +158,35 @@ func TestIPv4Sanity(t *testing.T) {
|
||||
// received with TTL less than 2.
|
||||
{
|
||||
name: "zero TTL",
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
TTL: 0,
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
name: "one TTL",
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
TTL: 1,
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
name: "End options",
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
TTL: ttl,
|
||||
options: []byte{0, 0, 0, 0},
|
||||
},
|
||||
{
|
||||
name: "NOP options",
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
TTL: ttl,
|
||||
options: []byte{1, 1, 1, 1},
|
||||
},
|
||||
{
|
||||
name: "NOP and End options",
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
TTL: ttl,
|
||||
options: []byte{1, 1, 0, 0},
|
||||
@@ -193,7 +194,7 @@ func TestIPv4Sanity(t *testing.T) {
|
||||
{
|
||||
name: "bad header length",
|
||||
headerLength: header.IPv4MinimumSize - 1,
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: uint8(header.ICMPv4ProtocolNumber),
|
||||
TTL: ttl,
|
||||
shouldFail: true,
|
||||
@@ -225,7 +226,7 @@ func TestIPv4Sanity(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "bad protocol",
|
||||
maxTotalLength: defaultMTU,
|
||||
maxTotalLength: ipv4.MaxTotalSize,
|
||||
transportProtocol: 99,
|
||||
TTL: ttl,
|
||||
shouldFail: true,
|
||||
@@ -462,7 +463,7 @@ var fragmentationTests = []struct {
|
||||
wantFragments []fragmentInfo
|
||||
}{
|
||||
{
|
||||
description: "No Fragmentation",
|
||||
description: "No fragmentation",
|
||||
mtu: 1280,
|
||||
gso: nil,
|
||||
transportHeaderLength: 0,
|
||||
@@ -482,6 +483,30 @@ var fragmentationTests = []struct {
|
||||
{offset: 1256, payloadSize: 744, more: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Fragmented with the minimum mtu",
|
||||
mtu: header.IPv4MinimumMTU,
|
||||
gso: nil,
|
||||
transportHeaderLength: 0,
|
||||
payloadSize: 100,
|
||||
wantFragments: []fragmentInfo{
|
||||
{offset: 0, payloadSize: 48, more: true},
|
||||
{offset: 48, payloadSize: 48, more: true},
|
||||
{offset: 96, payloadSize: 4, more: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Fragmented with mtu not a multiple of 8",
|
||||
mtu: header.IPv4MinimumMTU + 1,
|
||||
gso: nil,
|
||||
transportHeaderLength: 0,
|
||||
payloadSize: 100,
|
||||
wantFragments: []fragmentInfo{
|
||||
{offset: 0, payloadSize: 48, more: true},
|
||||
{offset: 48, payloadSize: 48, more: true},
|
||||
{offset: 96, payloadSize: 4, more: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "No fragmentation with big header",
|
||||
mtu: 2000,
|
||||
@@ -647,43 +672,50 @@ func TestFragmentationWritePackets(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestFragmentationErrors checks that errors are returned from write packet
|
||||
// TestFragmentationErrors checks that errors are returned from WritePacket
|
||||
// correctly.
|
||||
func TestFragmentationErrors(t *testing.T) {
|
||||
const ttl = 42
|
||||
|
||||
expectedError := tcpip.ErrAborted
|
||||
fragTests := []struct {
|
||||
tests := []struct {
|
||||
description string
|
||||
mtu uint32
|
||||
transportHeaderLength int
|
||||
payloadSize int
|
||||
allowPackets int
|
||||
fragmentCount int
|
||||
outgoingErrors int
|
||||
mockError *tcpip.Error
|
||||
wantError *tcpip.Error
|
||||
}{
|
||||
{
|
||||
description: "No frag",
|
||||
mtu: 2000,
|
||||
transportHeaderLength: 0,
|
||||
payloadSize: 1000,
|
||||
transportHeaderLength: 0,
|
||||
allowPackets: 0,
|
||||
fragmentCount: 1,
|
||||
outgoingErrors: 1,
|
||||
mockError: tcpip.ErrAborted,
|
||||
wantError: tcpip.ErrAborted,
|
||||
},
|
||||
{
|
||||
description: "Error on first frag",
|
||||
mtu: 500,
|
||||
transportHeaderLength: 0,
|
||||
payloadSize: 1000,
|
||||
transportHeaderLength: 0,
|
||||
allowPackets: 0,
|
||||
fragmentCount: 3,
|
||||
outgoingErrors: 3,
|
||||
mockError: tcpip.ErrAborted,
|
||||
wantError: tcpip.ErrAborted,
|
||||
},
|
||||
{
|
||||
description: "Error on second frag",
|
||||
mtu: 500,
|
||||
transportHeaderLength: 0,
|
||||
payloadSize: 1000,
|
||||
transportHeaderLength: 0,
|
||||
allowPackets: 1,
|
||||
fragmentCount: 3,
|
||||
outgoingErrors: 2,
|
||||
mockError: tcpip.ErrAborted,
|
||||
wantError: tcpip.ErrAborted,
|
||||
},
|
||||
{
|
||||
description: "Error on first frag MTU smaller than header",
|
||||
@@ -691,28 +723,40 @@ func TestFragmentationErrors(t *testing.T) {
|
||||
transportHeaderLength: 1000,
|
||||
payloadSize: 500,
|
||||
allowPackets: 0,
|
||||
fragmentCount: 4,
|
||||
outgoingErrors: 4,
|
||||
mockError: tcpip.ErrAborted,
|
||||
wantError: tcpip.ErrAborted,
|
||||
},
|
||||
{
|
||||
description: "Error when MTU is smaller than IPv4 minimum MTU",
|
||||
mtu: header.IPv4MinimumMTU - 1,
|
||||
transportHeaderLength: 0,
|
||||
payloadSize: 500,
|
||||
allowPackets: 0,
|
||||
outgoingErrors: 1,
|
||||
mockError: nil,
|
||||
wantError: tcpip.ErrInvalidEndpointState,
|
||||
},
|
||||
}
|
||||
|
||||
for _, ft := range fragTests {
|
||||
for _, ft := range tests {
|
||||
t.Run(ft.description, func(t *testing.T) {
|
||||
ep := testutil.NewMockLinkEndpoint(ft.mtu, expectedError, ft.allowPackets)
|
||||
r := buildRoute(t, ep)
|
||||
pkt := testutil.MakeRandPkt(ft.transportHeaderLength, extraHeaderReserve+header.IPv4MinimumSize, []int{ft.payloadSize}, header.IPv4ProtocolNumber)
|
||||
ep := testutil.NewMockLinkEndpoint(ft.mtu, ft.mockError, ft.allowPackets)
|
||||
r := buildRoute(t, ep)
|
||||
err := r.WritePacket(&stack.GSO{}, stack.NetworkHeaderParams{
|
||||
Protocol: tcp.ProtocolNumber,
|
||||
TTL: ttl,
|
||||
TOS: stack.DefaultTOS,
|
||||
}, pkt)
|
||||
if err != expectedError {
|
||||
t.Errorf("got WritePacket(_, _, _) = %s, want = %s", err, expectedError)
|
||||
if err != ft.wantError {
|
||||
t.Errorf("got WritePacket(_, _, _) = %s, want = %s", err, ft.wantError)
|
||||
}
|
||||
if got, want := len(ep.WrittenPackets), int(r.Stats().IP.PacketsSent.Value()); err != nil && got != want {
|
||||
t.Errorf("got len(ep.WrittenPackets) = %d, want = %d", got, want)
|
||||
if got := int(r.Stats().IP.PacketsSent.Value()); got != ft.allowPackets {
|
||||
t.Errorf("got r.Stats().IP.PacketsSent.Value() = %d, want = %d", got, ft.allowPackets)
|
||||
}
|
||||
if got, want := int(r.Stats().IP.OutgoingPacketErrors.Value()), ft.fragmentCount-ft.allowPackets; got != want {
|
||||
t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = %d", got, want)
|
||||
if got := int(r.Stats().IP.OutgoingPacketErrors.Value()); got != ft.outgoingErrors {
|
||||
t.Errorf("got r.Stats().IP.OutgoingPacketErrors.Value() = %d, want = %d", got, ft.outgoingErrors)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1577,7 +1621,7 @@ func TestWriteStats(t *testing.T) {
|
||||
t.Run(writer.name, func(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ep := testutil.NewMockLinkEndpoint(header.IPv4MinimumSize+header.UDPMinimumSize, tcpip.ErrInvalidEndpointState, test.allowPackets)
|
||||
ep := testutil.NewMockLinkEndpoint(header.IPv4MinimumMTU, tcpip.ErrInvalidEndpointState, test.allowPackets)
|
||||
rt := buildRoute(t, ep)
|
||||
|
||||
var pkts stack.PacketBufferList
|
||||
@@ -1783,7 +1827,7 @@ func TestPacketQueing(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
e := channel.New(1, header.IPv6MinimumMTU, host1NICLinkAddr)
|
||||
e := channel.New(1, defaultMTU, host1NICLinkAddr)
|
||||
e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol},
|
||||
|
||||
@@ -170,8 +170,11 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
return
|
||||
}
|
||||
pkt.Data.TrimFront(header.ICMPv6PacketTooBigMinimumSize)
|
||||
mtu := header.ICMPv6(hdr).MTU()
|
||||
e.handleControl(stack.ControlPacketTooBig, calculateMTU(mtu), pkt)
|
||||
networkMTU, err := calculateNetworkMTU(header.ICMPv6(hdr).MTU(), header.IPv6MinimumSize)
|
||||
if err != nil {
|
||||
networkMTU = 0
|
||||
}
|
||||
e.handleControl(stack.ControlPacketTooBig, networkMTU, pkt)
|
||||
|
||||
case header.ICMPv6DstUnreachable:
|
||||
received.DstUnreachable.Increment()
|
||||
|
||||
@@ -46,7 +46,7 @@ const (
|
||||
// ProtocolNumber is the ipv6 protocol number.
|
||||
ProtocolNumber = header.IPv6ProtocolNumber
|
||||
|
||||
// maxTotalSize is maximum size that can be encoded in the 16-bit
|
||||
// maxPayloadSize is the maximum size that can be encoded in the 16-bit
|
||||
// PayloadLength field of the ipv6 header.
|
||||
maxPayloadSize = 0xffff
|
||||
|
||||
@@ -363,7 +363,11 @@ func (e *endpoint) DefaultTTL() uint8 {
|
||||
// MTU implements stack.NetworkEndpoint.MTU. It returns the link-layer MTU minus
|
||||
// the network layer max header length.
|
||||
func (e *endpoint) MTU() uint32 {
|
||||
return calculateMTU(e.nic.MTU())
|
||||
networkMTU, err := calculateNetworkMTU(e.nic.MTU(), header.IPv6MinimumSize)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return networkMTU
|
||||
}
|
||||
|
||||
// MaxHeaderLength returns the maximum length needed by ipv6 headers (and
|
||||
@@ -386,27 +390,40 @@ func (e *endpoint) addIPHeader(r *stack.Route, pkt *stack.PacketBuffer, params s
|
||||
pkt.NetworkProtocolNumber = ProtocolNumber
|
||||
}
|
||||
|
||||
func (e *endpoint) packetMustBeFragmented(pkt *stack.PacketBuffer, gso *stack.GSO) bool {
|
||||
return (gso == nil || gso.Type == stack.GSONone) && pkt.Size() > int(e.nic.MTU())
|
||||
func packetMustBeFragmented(pkt *stack.PacketBuffer, networkMTU uint32, gso *stack.GSO) bool {
|
||||
payload := pkt.TransportHeader().View().Size() + pkt.Data.Size()
|
||||
return (gso == nil || gso.Type == stack.GSONone) && uint32(payload) > networkMTU
|
||||
}
|
||||
|
||||
// handleFragments fragments pkt and calls the handler function on each
|
||||
// fragment. It returns the number of fragments handled and the number of
|
||||
// fragments left to be processed. The IP header must already be present in the
|
||||
// original packet. The mtu is the maximum size of the packets. The transport
|
||||
// header protocol number is required to avoid parsing the IPv6 extension
|
||||
// headers.
|
||||
func (e *endpoint) handleFragments(r *stack.Route, gso *stack.GSO, mtu uint32, pkt *stack.PacketBuffer, transProto tcpip.TransportProtocolNumber, handler func(*stack.PacketBuffer) *tcpip.Error) (int, int, *tcpip.Error) {
|
||||
fragMTU := int(calculateFragmentInnerMTU(mtu, pkt))
|
||||
if fragMTU < pkt.TransportHeader().View().Size() {
|
||||
// original packet. The transport header protocol number is required to avoid
|
||||
// parsing the IPv6 extension headers.
|
||||
func (e *endpoint) handleFragments(r *stack.Route, gso *stack.GSO, networkMTU uint32, pkt *stack.PacketBuffer, transProto tcpip.TransportProtocolNumber, handler func(*stack.PacketBuffer) *tcpip.Error) (int, int, *tcpip.Error) {
|
||||
networkHeader := header.IPv6(pkt.NetworkHeader().View())
|
||||
|
||||
// TODO(gvisor.dev/issue/3912): Once the Authentication or ESP Headers are
|
||||
// supported for outbound packets, their length should not affect the fragment
|
||||
// maximum payload length because they should only be transmitted once.
|
||||
fragmentPayloadLen := (networkMTU - header.IPv6FragmentHeaderSize) &^ 7
|
||||
if fragmentPayloadLen < header.IPv6FragmentExtHdrFragmentOffsetBytesPerUnit {
|
||||
// We need at least 8 bytes of space left for the fragmentable part because
|
||||
// the fragment payload must obviously be non-zero and must be a multiple
|
||||
// of 8 as per RFC 8200 section 4.5:
|
||||
// Each complete fragment, except possibly the last ("rightmost") one, is
|
||||
// an integer multiple of 8 octets long.
|
||||
return 0, 1, tcpip.ErrMessageTooLong
|
||||
}
|
||||
|
||||
if fragmentPayloadLen < uint32(pkt.TransportHeader().View().Size()) {
|
||||
// As per RFC 8200 Section 4.5, the Transport Header is expected to be small
|
||||
// enough to fit in the first fragment.
|
||||
return 0, 1, tcpip.ErrMessageTooLong
|
||||
}
|
||||
|
||||
pf := fragmentation.MakePacketFragmenter(pkt, fragMTU, calculateFragmentReserve(pkt))
|
||||
pf := fragmentation.MakePacketFragmenter(pkt, fragmentPayloadLen, calculateFragmentReserve(pkt))
|
||||
id := atomic.AddUint32(&e.protocol.ids[hashRoute(r, e.protocol.hashIV)%buckets], 1)
|
||||
networkHeader := header.IPv6(pkt.NetworkHeader().View())
|
||||
|
||||
var n int
|
||||
for {
|
||||
@@ -468,8 +485,14 @@ func (e *endpoint) writePacket(r *stack.Route, gso *stack.GSO, pkt *stack.Packet
|
||||
return nil
|
||||
}
|
||||
|
||||
if e.packetMustBeFragmented(pkt, gso) {
|
||||
sent, remain, err := e.handleFragments(r, gso, e.nic.MTU(), pkt, protocol, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
networkMTU, err := calculateNetworkMTU(e.nic.MTU(), uint32(pkt.NetworkHeader().View().Size()))
|
||||
if err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
return err
|
||||
}
|
||||
|
||||
if packetMustBeFragmented(pkt, networkMTU, gso) {
|
||||
sent, remain, err := e.handleFragments(r, gso, networkMTU, pkt, protocol, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
// TODO(gvisor.dev/issue/3884): Evaluate whether we want to send each
|
||||
// fragment one by one using WritePacket() (current strategy) or if we
|
||||
// want to create a PacketBufferList from the fragments and feed it to
|
||||
@@ -499,13 +522,20 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
return pkts.Len(), nil
|
||||
}
|
||||
|
||||
linkMTU := e.nic.MTU()
|
||||
for pb := pkts.Front(); pb != nil; pb = pb.Next() {
|
||||
e.addIPHeader(r, pb, params)
|
||||
if e.packetMustBeFragmented(pb, gso) {
|
||||
|
||||
networkMTU, err := calculateNetworkMTU(linkMTU, uint32(pb.NetworkHeader().View().Size()))
|
||||
if err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(pkts.Len()))
|
||||
return 0, err
|
||||
}
|
||||
if packetMustBeFragmented(pb, networkMTU, gso) {
|
||||
// Keep track of the packet that is about to be fragmented so it can be
|
||||
// removed once the fragmentation is done.
|
||||
originalPkt := pb
|
||||
if _, _, err := e.handleFragments(r, gso, e.nic.MTU(), pb, params.Protocol, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
if _, _, err := e.handleFragments(r, gso, networkMTU, pb, params.Protocol, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
// Modify the packet list in place with the new fragments.
|
||||
pkts.InsertAfter(pb, fragPkt)
|
||||
pb = fragPkt
|
||||
@@ -569,7 +599,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
return n + len(dropped), nil
|
||||
}
|
||||
|
||||
// WriteHeaderIncludedPacker implements stack.NetworkEndpoint.
|
||||
// WriteHeaderIncludedPacket implements stack.NetworkEndpoint.
|
||||
func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
// The packet already has an IP header, but there are a few required checks.
|
||||
h, ok := pkt.Data.PullUp(header.IPv6MinimumSize)
|
||||
@@ -1427,14 +1457,31 @@ func (p *protocol) SetForwarding(v bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// calculateMTU calculates the network-layer payload MTU based on the link-layer
|
||||
// payload mtu.
|
||||
func calculateMTU(mtu uint32) uint32 {
|
||||
mtu -= header.IPv6MinimumSize
|
||||
if mtu <= maxPayloadSize {
|
||||
return mtu
|
||||
// calculateNetworkMTU calculates the network-layer payload MTU based on the
|
||||
// link-layer payload MTU and the length of every IPv6 header.
|
||||
// Note that this is different than the Payload Length field of the IPv6 header,
|
||||
// which includes the length of the extension headers.
|
||||
func calculateNetworkMTU(linkMTU, networkHeadersLen uint32) (uint32, *tcpip.Error) {
|
||||
if linkMTU < header.IPv6MinimumMTU {
|
||||
return 0, tcpip.ErrInvalidEndpointState
|
||||
}
|
||||
return maxPayloadSize
|
||||
|
||||
// As per RFC 7112 section 5, we should discard packets if their IPv6 header
|
||||
// is bigger than 1280 bytes (ie, the minimum link MTU) since we do not
|
||||
// support PMTU discovery:
|
||||
// Hosts that do not discover the Path MTU MUST limit the IPv6 Header Chain
|
||||
// length to 1280 bytes. Limiting the IPv6 Header Chain length to 1280
|
||||
// bytes ensures that the header chain length does not exceed the IPv6
|
||||
// minimum MTU.
|
||||
if networkHeadersLen > header.IPv6MinimumMTU {
|
||||
return 0, tcpip.ErrMalformedHeader
|
||||
}
|
||||
|
||||
networkMTU := linkMTU - uint32(networkHeadersLen)
|
||||
if networkMTU > maxPayloadSize {
|
||||
networkMTU = maxPayloadSize
|
||||
}
|
||||
return networkMTU, nil
|
||||
}
|
||||
|
||||
// Options holds options to configure a new protocol.
|
||||
@@ -1509,23 +1556,6 @@ func NewProtocol(s *stack.Stack) stack.NetworkProtocol {
|
||||
return NewProtocolWithOptions(Options{})(s)
|
||||
}
|
||||
|
||||
// calculateFragmentInnerMTU calculates the maximum number of bytes of
|
||||
// fragmentable data a fragment can have, based on the link layer mtu and pkt's
|
||||
// network header size.
|
||||
func calculateFragmentInnerMTU(mtu uint32, pkt *stack.PacketBuffer) uint32 {
|
||||
// TODO(gvisor.dev/issue/3912): Once the Authentication or ESP Headers are
|
||||
// supported for outbound packets, their length should not affect the fragment
|
||||
// MTU because they should only be transmitted once.
|
||||
mtu -= uint32(pkt.NetworkHeader().View().Size())
|
||||
mtu -= header.IPv6FragmentHeaderSize
|
||||
// Round the MTU down to align to 8 bytes.
|
||||
mtu &^= 7
|
||||
if mtu <= maxPayloadSize {
|
||||
return mtu
|
||||
}
|
||||
return maxPayloadSize
|
||||
}
|
||||
|
||||
func calculateFragmentReserve(pkt *stack.PacketBuffer) int {
|
||||
return pkt.AvailableHeaderBytes() + pkt.NetworkHeader().View().Size() + header.IPv6FragmentHeaderSize
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ func TestReceiveOnAllNodesMulticastAddr(t *testing.T) {
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{test.protocolFactory},
|
||||
})
|
||||
e := channel.New(10, 1280, linkAddr1)
|
||||
e := channel.New(10, header.IPv6MinimumMTU, linkAddr1)
|
||||
if err := s.CreateNIC(1, e); err != nil {
|
||||
t.Fatalf("CreateNIC(_) = %s", err)
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func TestReceiveOnSolicitedNodeAddr(t *testing.T) {
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{test.protocolFactory},
|
||||
})
|
||||
e := channel.New(1, 1280, linkAddr1)
|
||||
e := channel.New(1, header.IPv6MinimumMTU, linkAddr1)
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
|
||||
}
|
||||
@@ -825,7 +825,7 @@ func TestReceiveIPv6ExtHdrs(t *testing.T) {
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
|
||||
})
|
||||
e := channel.New(1, 1280, linkAddr1)
|
||||
e := channel.New(1, header.IPv6MinimumMTU, linkAddr1)
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
|
||||
}
|
||||
@@ -1844,7 +1844,7 @@ func TestReceiveIPv6Fragments(t *testing.T) {
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
|
||||
})
|
||||
e := channel.New(0, 1280, linkAddr1)
|
||||
e := channel.New(0, header.IPv6MinimumMTU, linkAddr1)
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
|
||||
}
|
||||
@@ -2230,8 +2230,8 @@ var fragmentationTests = []struct {
|
||||
wantFragments []fragmentInfo
|
||||
}{
|
||||
{
|
||||
description: "No Fragmentation",
|
||||
mtu: 1280,
|
||||
description: "No fragmentation",
|
||||
mtu: header.IPv6MinimumMTU,
|
||||
gso: nil,
|
||||
transHdrLen: 0,
|
||||
payloadSize: 1000,
|
||||
@@ -2241,7 +2241,18 @@ var fragmentationTests = []struct {
|
||||
},
|
||||
{
|
||||
description: "Fragmented",
|
||||
mtu: 1280,
|
||||
mtu: header.IPv6MinimumMTU,
|
||||
gso: nil,
|
||||
transHdrLen: 0,
|
||||
payloadSize: 2000,
|
||||
wantFragments: []fragmentInfo{
|
||||
{offset: 0, payloadSize: 1240, more: true},
|
||||
{offset: 154, payloadSize: 776, more: false},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Fragmented with mtu not a multiple of 8",
|
||||
mtu: header.IPv6MinimumMTU + 1,
|
||||
gso: nil,
|
||||
transHdrLen: 0,
|
||||
payloadSize: 2000,
|
||||
@@ -2262,7 +2273,7 @@ var fragmentationTests = []struct {
|
||||
},
|
||||
{
|
||||
description: "Fragmented with gso none",
|
||||
mtu: 1280,
|
||||
mtu: header.IPv6MinimumMTU,
|
||||
gso: &stack.GSO{Type: stack.GSONone},
|
||||
transHdrLen: 0,
|
||||
payloadSize: 1400,
|
||||
@@ -2273,7 +2284,7 @@ var fragmentationTests = []struct {
|
||||
},
|
||||
{
|
||||
description: "Fragmented with big header",
|
||||
mtu: 1280,
|
||||
mtu: header.IPv6MinimumMTU,
|
||||
gso: nil,
|
||||
transHdrLen: 100,
|
||||
payloadSize: 1200,
|
||||
@@ -2448,8 +2459,8 @@ func TestFragmentationErrors(t *testing.T) {
|
||||
wantError: tcpip.ErrAborted,
|
||||
},
|
||||
{
|
||||
description: "Error on packet with MTU smaller than transport header",
|
||||
mtu: 1280,
|
||||
description: "Error when MTU is smaller than transport header",
|
||||
mtu: header.IPv6MinimumMTU,
|
||||
transHdrLen: 1500,
|
||||
payloadSize: 500,
|
||||
allowPackets: 0,
|
||||
@@ -2457,6 +2468,16 @@ func TestFragmentationErrors(t *testing.T) {
|
||||
mockError: nil,
|
||||
wantError: tcpip.ErrMessageTooLong,
|
||||
},
|
||||
{
|
||||
description: "Error when MTU is smaller than IPv6 minimum MTU",
|
||||
mtu: header.IPv6MinimumMTU - 1,
|
||||
transHdrLen: 0,
|
||||
payloadSize: 500,
|
||||
allowPackets: 0,
|
||||
outgoingErrors: 1,
|
||||
mockError: nil,
|
||||
wantError: tcpip.ErrInvalidEndpointState,
|
||||
},
|
||||
}
|
||||
|
||||
for _, ft := range tests {
|
||||
|
||||
Reference in New Issue
Block a user