summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/network
diff options
context:
space:
mode:
authorGhanan Gowripalan <ghanan@google.com>2021-02-01 12:01:49 -0800
committergVisor bot <gvisor-bot@google.com>2021-02-01 12:04:03 -0800
commitebd3912c0f7e4255f100a00d2ab27304dac70daa (patch)
tree89e28a48e7fcd6015d2c2af25a565937cb1d61c9 /pkg/tcpip/network
parentcbcebfea80bd59091e142cc6dad4192915194550 (diff)
Refactor HandleControlPacket/SockError
...to remove the need for the transport layer to deduce the type of error it received. Rename HandleControlPacket to HandleError as HandleControlPacket only handles errors. tcpip.SockError now holds a tcpip.SockErrorCause interface that different errors can implement. PiperOrigin-RevId: 354994306
Diffstat (limited to 'pkg/tcpip/network')
-rw-r--r--pkg/tcpip/network/ip_test.go231
-rw-r--r--pkg/tcpip/network/ipv4/icmp.go112
-rw-r--r--pkg/tcpip/network/ipv4/ipv4.go2
-rw-r--r--pkg/tcpip/network/ipv6/icmp.go137
-rw-r--r--pkg/tcpip/network/ipv6/ipv6.go2
5 files changed, 426 insertions, 58 deletions
diff --git a/pkg/tcpip/network/ip_test.go b/pkg/tcpip/network/ip_test.go
index 8d155344b..6a1f11a36 100644
--- a/pkg/tcpip/network/ip_test.go
+++ b/pkg/tcpip/network/ip_test.go
@@ -59,6 +59,14 @@ var localIPv6AddrWithPrefix = tcpip.AddressWithPrefix{
PrefixLen: 120,
}
+type transportError struct {
+ origin tcpip.SockErrOrigin
+ typ uint8
+ code uint8
+ info uint32
+ kind stack.TransportErrorKind
+}
+
// testObject implements two interfaces: LinkEndpoint and TransportDispatcher.
// The former is used to pretend that it's a link endpoint so that we can
// inspect packets written by the network endpoints. The latter is used to
@@ -74,8 +82,7 @@ type testObject struct {
srcAddr tcpip.Address
dstAddr tcpip.Address
v4 bool
- typ stack.ControlType
- extra uint32
+ transErr transportError
dataCalls int
controlCalls int
@@ -119,16 +126,23 @@ func (t *testObject) DeliverTransportPacket(protocol tcpip.TransportProtocolNumb
return stack.TransportPacketHandled
}
-// DeliverTransportControlPacket is called by network endpoints after parsing
+// DeliverTransportError is called by network endpoints after parsing
// incoming control (ICMP) packets. This is used by the test object to verify
// that the results of the parsing are expected.
-func (t *testObject) DeliverTransportControlPacket(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, typ stack.ControlType, extra uint32, pkt *stack.PacketBuffer) {
+func (t *testObject) DeliverTransportError(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr stack.TransportError, pkt *stack.PacketBuffer) {
t.checkValues(trans, pkt.Data, remote, local)
- if typ != t.typ {
- t.t.Errorf("typ = %v, want %v", typ, t.typ)
- }
- if extra != t.extra {
- t.t.Errorf("extra = %v, want %v", extra, t.extra)
+ if diff := cmp.Diff(
+ t.transErr,
+ transportError{
+ origin: transErr.Origin(),
+ typ: transErr.Type(),
+ code: transErr.Code(),
+ info: transErr.Info(),
+ kind: transErr.Kind(),
+ },
+ cmp.AllowUnexported(transportError{}),
+ ); diff != "" {
+ t.t.Errorf("transport error mismatch (-want +got):\n%s", diff)
}
t.controlCalls++
}
@@ -702,24 +716,81 @@ func TestReceive(t *testing.T) {
}
func TestIPv4ReceiveControl(t *testing.T) {
- const mtu = 0xbeef - header.IPv4MinimumSize
+ const (
+ mtu = 0xbeef - header.IPv4MinimumSize
+ dataLen = 8
+ )
+
cases := []struct {
name string
expectedCount int
fragmentOffset uint16
code header.ICMPv4Code
- expectedTyp stack.ControlType
- expectedExtra uint32
+ transErr transportError
trunc int
}{
- {"FragmentationNeeded", 1, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 0},
- {"Truncated (10 bytes missing)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 10},
- {"Truncated (missing IPv4 header)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, header.IPv4MinimumSize + 8},
- {"Truncated (missing 'extra info')", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, 4 + header.IPv4MinimumSize + 8},
- {"Truncated (missing ICMP header)", 0, 0, header.ICMPv4FragmentationNeeded, stack.ControlPacketTooBig, mtu, header.ICMPv4MinimumSize + header.IPv4MinimumSize + 8},
- {"Port unreachable", 1, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 0},
- {"Non-zero fragment offset", 0, 100, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 0},
- {"Zero-length packet", 0, 0, header.ICMPv4PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv4MinimumSize + header.ICMPv4MinimumSize + 8},
+ {
+ name: "FragmentationNeeded",
+ expectedCount: 1,
+ fragmentOffset: 0,
+ code: header.ICMPv4FragmentationNeeded,
+ transErr: transportError{
+ origin: tcpip.SockExtErrorOriginICMP,
+ typ: uint8(header.ICMPv4DstUnreachable),
+ code: uint8(header.ICMPv4FragmentationNeeded),
+ info: mtu,
+ kind: stack.PacketTooBigTransportError,
+ },
+ trunc: 0,
+ },
+ {
+ name: "Truncated (missing IPv4 header)",
+ expectedCount: 0,
+ fragmentOffset: 0,
+ code: header.ICMPv4FragmentationNeeded,
+ trunc: header.IPv4MinimumSize + header.ICMPv4MinimumSize,
+ },
+ {
+ name: "Truncated (partial offending packet's IP header)",
+ expectedCount: 0,
+ fragmentOffset: 0,
+ code: header.ICMPv4FragmentationNeeded,
+ trunc: header.IPv4MinimumSize + header.ICMPv4MinimumSize + header.IPv4MinimumSize - 1,
+ },
+ {
+ name: "Truncated (partial offending packet's data)",
+ expectedCount: 0,
+ fragmentOffset: 0,
+ code: header.ICMPv4FragmentationNeeded,
+ trunc: header.ICMPv4MinimumSize + header.ICMPv4MinimumSize + header.IPv4MinimumSize + dataLen - 1,
+ },
+ {
+ name: "Port unreachable",
+ expectedCount: 1,
+ fragmentOffset: 0,
+ code: header.ICMPv4PortUnreachable,
+ transErr: transportError{
+ origin: tcpip.SockExtErrorOriginICMP,
+ typ: uint8(header.ICMPv4DstUnreachable),
+ code: uint8(header.ICMPv4PortUnreachable),
+ kind: stack.DestinationPortUnreachableTransportError,
+ },
+ trunc: 0,
+ },
+ {
+ name: "Non-zero fragment offset",
+ expectedCount: 0,
+ fragmentOffset: 100,
+ code: header.ICMPv4PortUnreachable,
+ trunc: 0,
+ },
+ {
+ name: "Zero-length packet",
+ expectedCount: 0,
+ fragmentOffset: 100,
+ code: header.ICMPv4PortUnreachable,
+ trunc: 2*header.IPv4MinimumSize + header.ICMPv4MinimumSize + dataLen,
+ },
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
@@ -738,7 +809,7 @@ func TestIPv4ReceiveControl(t *testing.T) {
}
const dataOffset = header.IPv4MinimumSize*2 + header.ICMPv4MinimumSize
- view := buffer.NewView(dataOffset + 8)
+ view := buffer.NewView(dataOffset + dataLen)
// Create the outer IPv4 header.
ip := header.IPv4(view)
@@ -785,8 +856,7 @@ func TestIPv4ReceiveControl(t *testing.T) {
nic.testObject.srcAddr = remoteIPv4Addr
nic.testObject.dstAddr = localIPv4Addr
nic.testObject.contents = view[dataOffset:]
- nic.testObject.typ = c.expectedTyp
- nic.testObject.extra = c.expectedExtra
+ nic.testObject.transErr = c.transErr
addressableEndpoint, ok := ep.(stack.AddressableEndpoint)
if !ok {
@@ -953,30 +1023,112 @@ func TestIPv6Send(t *testing.T) {
}
func TestIPv6ReceiveControl(t *testing.T) {
+ const (
+ mtu = 0xffff
+ outerSrcAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa"
+ dataLen = 8
+ )
+
newUint16 := func(v uint16) *uint16 { return &v }
- const mtu = 0xffff
- const outerSrcAddr = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa"
+ portUnreachableTransErr := transportError{
+ origin: tcpip.SockExtErrorOriginICMP6,
+ typ: uint8(header.ICMPv6DstUnreachable),
+ code: uint8(header.ICMPv6PortUnreachable),
+ kind: stack.DestinationPortUnreachableTransportError,
+ }
+
cases := []struct {
name string
expectedCount int
fragmentOffset *uint16
typ header.ICMPv6Type
code header.ICMPv6Code
- expectedTyp stack.ControlType
- expectedExtra uint32
+ transErr transportError
trunc int
}{
- {"PacketTooBig", 1, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 0},
- {"Truncated (10 bytes missing)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 10},
- {"Truncated (missing IPv6 header)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, header.IPv6MinimumSize + 8},
- {"Truncated PacketTooBig (missing 'extra info')", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, 4 + header.IPv6MinimumSize + 8},
- {"Truncated (missing ICMP header)", 0, nil, header.ICMPv6PacketTooBig, 0, stack.ControlPacketTooBig, mtu, header.ICMPv6PacketTooBigMinimumSize + header.IPv6MinimumSize + 8},
- {"Port unreachable", 1, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0},
- {"Truncated DstUnreachable (missing 'extra info')", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 4 + header.IPv6MinimumSize + 8},
- {"Fragmented, zero offset", 1, newUint16(0), header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0},
- {"Non-zero fragment offset", 0, newUint16(100), header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 0},
- {"Zero-length packet", 0, nil, header.ICMPv6DstUnreachable, header.ICMPv6PortUnreachable, stack.ControlPortUnreachable, 0, 2*header.IPv6MinimumSize + header.ICMPv6DstUnreachableMinimumSize + 8},
+ {
+ name: "PacketTooBig",
+ expectedCount: 1,
+ fragmentOffset: nil,
+ typ: header.ICMPv6PacketTooBig,
+ code: header.ICMPv6UnusedCode,
+ transErr: transportError{
+ origin: tcpip.SockExtErrorOriginICMP6,
+ typ: uint8(header.ICMPv6PacketTooBig),
+ code: uint8(header.ICMPv6UnusedCode),
+ info: mtu,
+ kind: stack.PacketTooBigTransportError,
+ },
+ trunc: 0,
+ },
+ {
+ name: "Truncated (missing offending packet's IPv6 header)",
+ expectedCount: 0,
+ fragmentOffset: nil,
+ typ: header.ICMPv6PacketTooBig,
+ code: header.ICMPv6UnusedCode,
+ trunc: header.IPv6MinimumSize + header.ICMPv6PacketTooBigMinimumSize,
+ },
+ {
+ name: "Truncated PacketTooBig (partial offending packet's IPv6 header)",
+ expectedCount: 0,
+ fragmentOffset: nil,
+ typ: header.ICMPv6PacketTooBig,
+ code: header.ICMPv6UnusedCode,
+ trunc: header.IPv6MinimumSize + header.ICMPv6PacketTooBigMinimumSize + header.IPv6MinimumSize - 1,
+ },
+ {
+ name: "Truncated (partial offending packet's data)",
+ expectedCount: 0,
+ fragmentOffset: nil,
+ typ: header.ICMPv6PacketTooBig,
+ code: header.ICMPv6UnusedCode,
+ trunc: header.IPv6MinimumSize + header.ICMPv6PacketTooBigMinimumSize + header.IPv6MinimumSize + dataLen - 1,
+ },
+ {
+ name: "Port unreachable",
+ expectedCount: 1,
+ fragmentOffset: nil,
+ typ: header.ICMPv6DstUnreachable,
+ code: header.ICMPv6PortUnreachable,
+ transErr: portUnreachableTransErr,
+ trunc: 0,
+ },
+ {
+ name: "Truncated DstPortUnreachable (partial offending packet's IP header)",
+ expectedCount: 0,
+ fragmentOffset: nil,
+ typ: header.ICMPv6DstUnreachable,
+ code: header.ICMPv6PortUnreachable,
+ trunc: header.IPv6MinimumSize + header.ICMPv6DstUnreachableMinimumSize + header.IPv6MinimumSize - 1,
+ },
+ {
+ name: "DstPortUnreachable for Fragmented, zero offset",
+ expectedCount: 1,
+ fragmentOffset: newUint16(0),
+ typ: header.ICMPv6DstUnreachable,
+ code: header.ICMPv6PortUnreachable,
+ transErr: portUnreachableTransErr,
+ trunc: 0,
+ },
+ {
+ name: "DstPortUnreachable for Non-zero fragment offset",
+ expectedCount: 0,
+ fragmentOffset: newUint16(100),
+ typ: header.ICMPv6DstUnreachable,
+ code: header.ICMPv6PortUnreachable,
+ transErr: portUnreachableTransErr,
+ trunc: 0,
+ },
+ {
+ name: "Zero-length packet",
+ expectedCount: 0,
+ fragmentOffset: nil,
+ typ: header.ICMPv6DstUnreachable,
+ code: header.ICMPv6PortUnreachable,
+ trunc: 2*header.IPv6MinimumSize + header.ICMPv6DstUnreachableMinimumSize + dataLen,
+ },
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
@@ -998,7 +1150,7 @@ func TestIPv6ReceiveControl(t *testing.T) {
if c.fragmentOffset != nil {
dataOffset += header.IPv6FragmentHeaderSize
}
- view := buffer.NewView(dataOffset + 8)
+ view := buffer.NewView(dataOffset + dataLen)
// Create the outer IPv6 header.
ip := header.IPv6(view)
@@ -1049,8 +1201,7 @@ func TestIPv6ReceiveControl(t *testing.T) {
nic.testObject.srcAddr = remoteIPv6Addr
nic.testObject.dstAddr = localIPv6Addr
nic.testObject.contents = view[dataOffset:]
- nic.testObject.typ = c.expectedTyp
- nic.testObject.extra = c.expectedExtra
+ nic.testObject.transErr = c.transErr
// Set ICMPv6 checksum.
icmp.SetChecksum(header.ICMPv6Checksum(icmp, outerSrcAddr, localIPv6Addr, buffer.VectorisedView{}))
diff --git a/pkg/tcpip/network/ipv4/icmp.go b/pkg/tcpip/network/ipv4/icmp.go
index 3d93a2cd0..74e70e283 100644
--- a/pkg/tcpip/network/ipv4/icmp.go
+++ b/pkg/tcpip/network/ipv4/icmp.go
@@ -23,11 +23,108 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
+// icmpv4DestinationUnreachableSockError is a general ICMPv4 Destination
+// Unreachable error.
+//
+// +stateify savable
+type icmpv4DestinationUnreachableSockError struct{}
+
+// Origin implements tcpip.SockErrorCause.
+func (*icmpv4DestinationUnreachableSockError) Origin() tcpip.SockErrOrigin {
+ return tcpip.SockExtErrorOriginICMP
+}
+
+// Type implements tcpip.SockErrorCause.
+func (*icmpv4DestinationUnreachableSockError) Type() uint8 {
+ return uint8(header.ICMPv4DstUnreachable)
+}
+
+// Info implements tcpip.SockErrorCause.
+func (*icmpv4DestinationUnreachableSockError) Info() uint32 {
+ return 0
+}
+
+var _ stack.TransportError = (*icmpv4DestinationHostUnreachableSockError)(nil)
+
+// icmpv4DestinationHostUnreachableSockError is an ICMPv4 Destination Host
+// Unreachable error.
+//
+// It indicates that a packet was not able to reach the destination host.
+//
+// +stateify savable
+type icmpv4DestinationHostUnreachableSockError struct {
+ icmpv4DestinationUnreachableSockError
+}
+
+// Code implements tcpip.SockErrorCause.
+func (*icmpv4DestinationHostUnreachableSockError) Code() uint8 {
+ return uint8(header.ICMPv4HostUnreachable)
+}
+
+// Kind implements stack.TransportError.
+func (*icmpv4DestinationHostUnreachableSockError) Kind() stack.TransportErrorKind {
+ return stack.DestinationHostUnreachableTransportError
+}
+
+var _ stack.TransportError = (*icmpv4DestinationPortUnreachableSockError)(nil)
+
+// icmpv4DestinationPortUnreachableSockError is an ICMPv4 Destination Port
+// Unreachable error.
+//
+// It indicates that a packet reached the destination host, but the transport
+// protocol was not active on the destination port.
+//
+// +stateify savable
+type icmpv4DestinationPortUnreachableSockError struct {
+ icmpv4DestinationUnreachableSockError
+}
+
+// Code implements tcpip.SockErrorCause.
+func (*icmpv4DestinationPortUnreachableSockError) Code() uint8 {
+ return uint8(header.ICMPv4PortUnreachable)
+}
+
+// Kind implements stack.TransportError.
+func (*icmpv4DestinationPortUnreachableSockError) Kind() stack.TransportErrorKind {
+ return stack.DestinationPortUnreachableTransportError
+}
+
+var _ stack.TransportError = (*icmpv4FragmentationNeededSockError)(nil)
+
+// icmpv4FragmentationNeededSockError is an ICMPv4 Destination Unreachable error
+// due to fragmentation being required but the packet was set to not be
+// fragmented.
+//
+// It indicates that a link exists on the path to the destination with an MTU
+// that is too small to carry the packet.
+//
+// +stateify savable
+type icmpv4FragmentationNeededSockError struct {
+ icmpv4DestinationUnreachableSockError
+
+ mtu uint32
+}
+
+// Code implements tcpip.SockErrorCause.
+func (*icmpv4FragmentationNeededSockError) Code() uint8 {
+ return uint8(header.ICMPv4FragmentationNeeded)
+}
+
+// Info implements tcpip.SockErrorCause.
+func (e *icmpv4FragmentationNeededSockError) Info() uint32 {
+ return e.mtu
+}
+
+// Kind implements stack.TransportError.
+func (*icmpv4FragmentationNeededSockError) Kind() stack.TransportErrorKind {
+ return stack.PacketTooBigTransportError
+}
+
// handleControl handles the case when an ICMP error packet contains the headers
// of the original packet that caused the ICMP one to be sent. This information
// is used to find out which transport endpoint must be notified about the ICMP
// packet. We only expect the payload, not the enclosing ICMP packet.
-func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt *stack.PacketBuffer) {
+func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.PacketBuffer) {
h, ok := pkt.Data.PullUp(header.IPv4MinimumSize)
if !ok {
return
@@ -54,10 +151,10 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt *stack
return
}
- // Skip the ip header, then deliver control message.
+ // Skip the ip header, then deliver the error.
pkt.Data.TrimFront(hlen)
p := hdr.TransportProtocol()
- e.dispatcher.DeliverTransportControlPacket(srcAddr, hdr.DestinationAddress(), ProtocolNumber, p, typ, extra, pkt)
+ e.dispatcher.DeliverTransportError(srcAddr, hdr.DestinationAddress(), ProtocolNumber, p, errInfo, pkt)
}
func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
@@ -222,19 +319,16 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
pkt.Data.TrimFront(header.ICMPv4MinimumSize)
switch h.Code() {
case header.ICMPv4HostUnreachable:
- e.handleControl(stack.ControlNoRoute, 0, pkt)
-
+ e.handleControl(&icmpv4DestinationHostUnreachableSockError{}, pkt)
case header.ICMPv4PortUnreachable:
- e.handleControl(stack.ControlPortUnreachable, 0, pkt)
-
+ e.handleControl(&icmpv4DestinationPortUnreachableSockError{}, pkt)
case header.ICMPv4FragmentationNeeded:
networkMTU, err := calculateNetworkMTU(uint32(h.MTU()), header.IPv4MinimumSize)
if err != nil {
networkMTU = 0
}
- e.handleControl(stack.ControlPacketTooBig, networkMTU, pkt)
+ e.handleControl(&icmpv4FragmentationNeededSockError{mtu: networkMTU}, pkt)
}
-
case header.ICMPv4SrcQuench:
received.srcQuench.Increment()
diff --git a/pkg/tcpip/network/ipv4/ipv4.go b/pkg/tcpip/network/ipv4/ipv4.go
index e146844c2..b2d626107 100644
--- a/pkg/tcpip/network/ipv4/ipv4.go
+++ b/pkg/tcpip/network/ipv4/ipv4.go
@@ -101,7 +101,7 @@ func (e *endpoint) HandleLinkResolutionFailure(pkt *stack.PacketBuffer) {
// Use the same control type as an ICMPv4 destination host unreachable error
// since the host is considered unreachable if we cannot resolve the link
// address to the next hop.
- e.handleControl(stack.ControlNoRoute, 0, pkt)
+ e.handleControl(&icmpv4DestinationHostUnreachableSockError{}, pkt)
}
// NewEndpoint creates a new ipv4 endpoint.
diff --git a/pkg/tcpip/network/ipv6/icmp.go b/pkg/tcpip/network/ipv6/icmp.go
index 12e5ead5e..dcfd93bab 100644
--- a/pkg/tcpip/network/ipv6/icmp.go
+++ b/pkg/tcpip/network/ipv6/icmp.go
@@ -23,11 +23,136 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
+// icmpv6DestinationUnreachableSockError is a general ICMPv6 Destination
+// Unreachable error.
+//
+// +stateify savable
+type icmpv6DestinationUnreachableSockError struct{}
+
+// Origin implements tcpip.SockErrorCause.
+func (*icmpv6DestinationUnreachableSockError) Origin() tcpip.SockErrOrigin {
+ return tcpip.SockExtErrorOriginICMP6
+}
+
+// Type implements tcpip.SockErrorCause.
+func (*icmpv6DestinationUnreachableSockError) Type() uint8 {
+ return uint8(header.ICMPv6DstUnreachable)
+}
+
+// Info implements tcpip.SockErrorCause.
+func (*icmpv6DestinationUnreachableSockError) Info() uint32 {
+ return 0
+}
+
+var _ stack.TransportError = (*icmpv6DestinationNetworkUnreachableSockError)(nil)
+
+// icmpv6DestinationNetworkUnreachableSockError is an ICMPv6 Destination Network
+// Unreachable error.
+//
+// It indicates that the destination network is unreachable.
+//
+// +stateify savable
+type icmpv6DestinationNetworkUnreachableSockError struct {
+ icmpv6DestinationUnreachableSockError
+}
+
+// Code implements tcpip.SockErrorCause.
+func (*icmpv6DestinationNetworkUnreachableSockError) Code() uint8 {
+ return uint8(header.ICMPv6NetworkUnreachable)
+}
+
+// Kind implements stack.TransportError.
+func (*icmpv6DestinationNetworkUnreachableSockError) Kind() stack.TransportErrorKind {
+ return stack.DestinationNetworkUnreachableTransportError
+}
+
+var _ stack.TransportError = (*icmpv6DestinationPortUnreachableSockError)(nil)
+
+// icmpv6DestinationPortUnreachableSockError is an ICMPv6 Destination Port
+// Unreachable error.
+//
+// It indicates that a packet reached the destination host, but the transport
+// protocol was not active on the destination port.
+//
+// +stateify savable
+type icmpv6DestinationPortUnreachableSockError struct {
+ icmpv6DestinationUnreachableSockError
+}
+
+// Code implements tcpip.SockErrorCause.
+func (*icmpv6DestinationPortUnreachableSockError) Code() uint8 {
+ return uint8(header.ICMPv6PortUnreachable)
+}
+
+// Kind implements stack.TransportError.
+func (*icmpv6DestinationPortUnreachableSockError) Kind() stack.TransportErrorKind {
+ return stack.DestinationPortUnreachableTransportError
+}
+
+var _ stack.TransportError = (*icmpv6DestinationAddressUnreachableSockError)(nil)
+
+// icmpv6DestinationAddressUnreachableSockError is an ICMPv6 Destination Address
+// Unreachable error.
+//
+// It indicates that a packet was not able to reach the destination.
+//
+// +stateify savable
+type icmpv6DestinationAddressUnreachableSockError struct {
+ icmpv6DestinationUnreachableSockError
+}
+
+// Code implements tcpip.SockErrorCause.
+func (*icmpv6DestinationAddressUnreachableSockError) Code() uint8 {
+ return uint8(header.ICMPv6AddressUnreachable)
+}
+
+// Kind implements stack.TransportError.
+func (*icmpv6DestinationAddressUnreachableSockError) Kind() stack.TransportErrorKind {
+ return stack.DestinationHostUnreachableTransportError
+}
+
+var _ stack.TransportError = (*icmpv6PacketTooBigSockError)(nil)
+
+// icmpv6PacketTooBigSockError is an ICMPv6 Packet Too Big error.
+//
+// It indicates that a link exists on the path to the destination with an MTU
+// that is too small to carry the packet.
+//
+// +stateify savable
+type icmpv6PacketTooBigSockError struct {
+ mtu uint32
+}
+
+// Origin implements tcpip.SockErrorCause.
+func (*icmpv6PacketTooBigSockError) Origin() tcpip.SockErrOrigin {
+ return tcpip.SockExtErrorOriginICMP6
+}
+
+// Type implements tcpip.SockErrorCause.
+func (*icmpv6PacketTooBigSockError) Type() uint8 {
+ return uint8(header.ICMPv6PacketTooBig)
+}
+
+// Code implements tcpip.SockErrorCause.
+func (*icmpv6PacketTooBigSockError) Code() uint8 {
+ return uint8(header.ICMPv6UnusedCode)
+}
+
+// Info implements tcpip.SockErrorCause.
+func (e *icmpv6PacketTooBigSockError) Info() uint32 {
+ return e.mtu
+}
+
+// Kind implements stack.TransportError.
+func (*icmpv6PacketTooBigSockError) Kind() stack.TransportErrorKind {
+ return stack.PacketTooBigTransportError
+}
+
// handleControl handles the case when an ICMP packet contains the headers of
// the original packet that caused the ICMP one to be sent. This information is
// used to find out which transport endpoint must be notified about the ICMP
// packet.
-func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt *stack.PacketBuffer) {
+func (e *endpoint) handleControl(transErr stack.TransportError, pkt *stack.PacketBuffer) {
h, ok := pkt.Data.PullUp(header.IPv6MinimumSize)
if !ok {
return
@@ -67,8 +192,7 @@ func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, pkt *stack
p = fragHdr.TransportProtocol()
}
- // Deliver the control packet to the transport endpoint.
- e.dispatcher.DeliverTransportControlPacket(src, hdr.DestinationAddress(), ProtocolNumber, p, typ, extra, pkt)
+ e.dispatcher.DeliverTransportError(src, hdr.DestinationAddress(), ProtocolNumber, p, transErr, pkt)
}
// getLinkAddrOption searches NDP options for a given link address option using
@@ -175,7 +299,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool) {
if err != nil {
networkMTU = 0
}
- e.handleControl(stack.ControlPacketTooBig, networkMTU, pkt)
+ e.handleControl(&icmpv6PacketTooBigSockError{mtu: networkMTU}, pkt)
case header.ICMPv6DstUnreachable:
received.dstUnreachable.Increment()
@@ -187,11 +311,10 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool) {
pkt.Data.TrimFront(header.ICMPv6DstUnreachableMinimumSize)
switch header.ICMPv6(hdr).Code() {
case header.ICMPv6NetworkUnreachable:
- e.handleControl(stack.ControlNetworkUnreachable, 0, pkt)
+ e.handleControl(&icmpv6DestinationNetworkUnreachableSockError{}, pkt)
case header.ICMPv6PortUnreachable:
- e.handleControl(stack.ControlPortUnreachable, 0, pkt)
+ e.handleControl(&icmpv6DestinationPortUnreachableSockError{}, pkt)
}
-
case header.ICMPv6NeighborSolicit:
received.neighborSolicit.Increment()
if !isNDPValid() || pkt.Data.Size() < header.ICMPv6NeighborSolicitMinimumSize {
diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go
index e56eb5796..c2e8c3ea7 100644
--- a/pkg/tcpip/network/ipv6/ipv6.go
+++ b/pkg/tcpip/network/ipv6/ipv6.go
@@ -235,7 +235,7 @@ func (e *endpoint) HandleLinkResolutionFailure(pkt *stack.PacketBuffer) {
})
pkt.NICID = e.nic.ID()
pkt.NetworkProtocolNumber = ProtocolNumber
- e.handleControl(stack.ControlAddressUnreachable, 0, pkt)
+ e.handleControl(&icmpv6DestinationAddressUnreachableSockError{}, pkt)
}
// onAddressAssignedLocked handles an address being assigned.