mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Do not resolve routes immediately
When a response needs to be sent to an incoming packet, the stack should consult its neighbour table to determine the remote address's link address. When an entry does not exist in the stack's neighbor table, the stack should queue the packet while link resolution completes. See comments. PiperOrigin-RevId: 336185457
This commit is contained in:
committed by
gVisor bot
parent
40269d0c24
commit
6768e6c59e
@@ -17,6 +17,7 @@ go_library(
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/syserror",
|
||||
"//pkg/tcpip/link/tun",
|
||||
"//pkg/tcpip/network/arp",
|
||||
"//pkg/usermem",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package tundev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
@@ -26,6 +28,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/tun"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/arp"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
@@ -84,7 +87,16 @@ func (fd *tunFD) Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArg
|
||||
return 0, err
|
||||
}
|
||||
flags := usermem.ByteOrder.Uint16(req.Data[:])
|
||||
return 0, fd.device.SetIff(stack.Stack, req.Name(), flags)
|
||||
created, err := fd.device.SetIff(stack.Stack, req.Name(), flags)
|
||||
if err == nil && created {
|
||||
// Always start with an ARP address for interfaces so they can handle ARP
|
||||
// packets.
|
||||
nicID := fd.device.NICID()
|
||||
if err := stack.Stack.AddAddress(nicID, arp.ProtocolNumber, arp.ProtocolAddress); err != nil {
|
||||
panic(fmt.Sprintf("failed to add ARP address after creating new TUN/TAP interface with ID = %d", nicID))
|
||||
}
|
||||
}
|
||||
return 0, err
|
||||
|
||||
case linux.TUNGETIFF:
|
||||
var req linux.IFReq
|
||||
|
||||
@@ -34,6 +34,7 @@ go_library(
|
||||
"//pkg/sentry/socket/netstack",
|
||||
"//pkg/syserror",
|
||||
"//pkg/tcpip/link/tun",
|
||||
"//pkg/tcpip/network/arp",
|
||||
"//pkg/usermem",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package dev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
@@ -25,6 +27,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netstack"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/tun"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/arp"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
@@ -60,7 +63,7 @@ func newNetTunDevice(ctx context.Context, owner fs.FileOwner, mode linux.FileMod
|
||||
}
|
||||
|
||||
// GetFile implements fs.InodeOperations.GetFile.
|
||||
func (iops *netTunInodeOperations) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
|
||||
func (*netTunInodeOperations) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
|
||||
return fs.NewFile(ctx, d, flags, &netTunFileOperations{}), nil
|
||||
}
|
||||
|
||||
@@ -80,12 +83,12 @@ type netTunFileOperations struct {
|
||||
var _ fs.FileOperations = (*netTunFileOperations)(nil)
|
||||
|
||||
// Release implements fs.FileOperations.Release.
|
||||
func (fops *netTunFileOperations) Release(ctx context.Context) {
|
||||
fops.device.Release(ctx)
|
||||
func (n *netTunFileOperations) Release(ctx context.Context) {
|
||||
n.device.Release(ctx)
|
||||
}
|
||||
|
||||
// Ioctl implements fs.FileOperations.Ioctl.
|
||||
func (fops *netTunFileOperations) Ioctl(ctx context.Context, file *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
|
||||
func (n *netTunFileOperations) Ioctl(ctx context.Context, file *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
|
||||
request := args[1].Uint()
|
||||
data := args[2].Pointer()
|
||||
|
||||
@@ -109,16 +112,25 @@ func (fops *netTunFileOperations) Ioctl(ctx context.Context, file *fs.File, io u
|
||||
return 0, err
|
||||
}
|
||||
flags := usermem.ByteOrder.Uint16(req.Data[:])
|
||||
return 0, fops.device.SetIff(stack.Stack, req.Name(), flags)
|
||||
created, err := n.device.SetIff(stack.Stack, req.Name(), flags)
|
||||
if err == nil && created {
|
||||
// Always start with an ARP address for interfaces so they can handle ARP
|
||||
// packets.
|
||||
nicID := n.device.NICID()
|
||||
if err := stack.Stack.AddAddress(nicID, arp.ProtocolNumber, arp.ProtocolAddress); err != nil {
|
||||
panic(fmt.Sprintf("failed to add ARP address after creating new TUN/TAP interface with ID = %d", nicID))
|
||||
}
|
||||
}
|
||||
return 0, err
|
||||
|
||||
case linux.TUNGETIFF:
|
||||
var req linux.IFReq
|
||||
|
||||
copy(req.IFName[:], fops.device.Name())
|
||||
copy(req.IFName[:], n.device.Name())
|
||||
|
||||
// Linux adds IFF_NOFILTER (the same value as IFF_NO_PI unfortunately) when
|
||||
// there is no sk_filter. See __tun_chr_ioctl() in net/drivers/tun.c.
|
||||
flags := fops.device.Flags() | linux.IFF_NOFILTER
|
||||
flags := n.device.Flags() | linux.IFF_NOFILTER
|
||||
usermem.ByteOrder.PutUint16(req.Data[:], flags)
|
||||
|
||||
_, err := req.CopyOut(t, data)
|
||||
@@ -130,41 +142,41 @@ func (fops *netTunFileOperations) Ioctl(ctx context.Context, file *fs.File, io u
|
||||
}
|
||||
|
||||
// Write implements fs.FileOperations.Write.
|
||||
func (fops *netTunFileOperations) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
func (n *netTunFileOperations) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
data := make([]byte, src.NumBytes())
|
||||
if _, err := src.CopyIn(ctx, data); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return fops.device.Write(data)
|
||||
return n.device.Write(data)
|
||||
}
|
||||
|
||||
// Read implements fs.FileOperations.Read.
|
||||
func (fops *netTunFileOperations) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) {
|
||||
data, err := fops.device.Read()
|
||||
func (n *netTunFileOperations) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) {
|
||||
data, err := n.device.Read()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n, err := dst.CopyOut(ctx, data)
|
||||
if n > 0 && n < len(data) {
|
||||
bytesCopied, err := dst.CopyOut(ctx, data)
|
||||
if bytesCopied > 0 && bytesCopied < len(data) {
|
||||
// Not an error for partial copying. Packet truncated.
|
||||
err = nil
|
||||
}
|
||||
return int64(n), err
|
||||
return int64(bytesCopied), err
|
||||
}
|
||||
|
||||
// Readiness implements watier.Waitable.Readiness.
|
||||
func (fops *netTunFileOperations) Readiness(mask waiter.EventMask) waiter.EventMask {
|
||||
return fops.device.Readiness(mask)
|
||||
func (n *netTunFileOperations) Readiness(mask waiter.EventMask) waiter.EventMask {
|
||||
return n.device.Readiness(mask)
|
||||
}
|
||||
|
||||
// EventRegister implements watier.Waitable.EventRegister.
|
||||
func (fops *netTunFileOperations) EventRegister(e *waiter.Entry, mask waiter.EventMask) {
|
||||
fops.device.EventRegister(e, mask)
|
||||
func (n *netTunFileOperations) EventRegister(e *waiter.Entry, mask waiter.EventMask) {
|
||||
n.device.EventRegister(e, mask)
|
||||
}
|
||||
|
||||
// EventUnregister implements watier.Waitable.EventUnregister.
|
||||
func (fops *netTunFileOperations) EventUnregister(e *waiter.Entry) {
|
||||
fops.device.EventUnregister(e)
|
||||
func (n *netTunFileOperations) EventUnregister(e *waiter.Entry) {
|
||||
n.device.EventUnregister(e)
|
||||
}
|
||||
|
||||
// isNetTunSupported returns whether /dev/net/tun device is supported for s.
|
||||
|
||||
+11
-5
@@ -117,25 +117,31 @@ func (b Ethernet) Encode(e *EthernetFields) {
|
||||
copy(b[dstMAC:][:EthernetAddressSize], e.DstAddr)
|
||||
}
|
||||
|
||||
// IsValidUnicastEthernetAddress returns true if addr is a valid unicast
|
||||
// IsMulticastEthernetAddress returns true if the address is a multicast
|
||||
// ethernet address.
|
||||
func IsMulticastEthernetAddress(addr tcpip.LinkAddress) bool {
|
||||
if len(addr) != EthernetAddressSize {
|
||||
return false
|
||||
}
|
||||
|
||||
return addr[unicastMulticastFlagByteIdx]&unicastMulticastFlagMask != 0
|
||||
}
|
||||
|
||||
// IsValidUnicastEthernetAddress returns true if the address is a unicast
|
||||
// ethernet address.
|
||||
func IsValidUnicastEthernetAddress(addr tcpip.LinkAddress) bool {
|
||||
// Must be of the right length.
|
||||
if len(addr) != EthernetAddressSize {
|
||||
return false
|
||||
}
|
||||
|
||||
// Must not be unspecified.
|
||||
if addr == unspecifiedEthernetAddress {
|
||||
return false
|
||||
}
|
||||
|
||||
// Must not be a multicast.
|
||||
if addr[unicastMulticastFlagByteIdx]&unicastMulticastFlagMask != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// addr is a valid unicast ethernet address.
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,53 @@ func TestIsValidUnicastEthernetAddress(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsMulticastEthernetAddress(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
addr tcpip.LinkAddress
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
"Nil",
|
||||
tcpip.LinkAddress([]byte(nil)),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Empty",
|
||||
tcpip.LinkAddress(""),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"InvalidLength",
|
||||
tcpip.LinkAddress("\x01\x02\x03"),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Unspecified",
|
||||
unspecifiedEthernetAddress,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Multicast",
|
||||
tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Unicast",
|
||||
tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06"),
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if got := IsMulticastEthernetAddress(test.addr); got != test.expected {
|
||||
t.Fatalf("got IsMulticastEthernetAddress = %t, want = %t", got, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthernetAddressFromMulticastIPv4Address(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
load("//tools:defs.bzl", "go_library")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_library(
|
||||
name = "pipe",
|
||||
srcs = ["pipe.go"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/buffer",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/stack",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,124 @@
|
||||
// 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 pipe provides the implementation of pipe-like data-link layer
|
||||
// endpoints. Such endpoints allow packets to be sent between two interfaces.
|
||||
package pipe
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
var _ stack.LinkEndpoint = (*Endpoint)(nil)
|
||||
|
||||
// New returns both ends of a new pipe.
|
||||
func New(linkAddr1, linkAddr2 tcpip.LinkAddress, capabilities stack.LinkEndpointCapabilities) (*Endpoint, *Endpoint) {
|
||||
ep1 := &Endpoint{
|
||||
linkAddr: linkAddr1,
|
||||
capabilities: capabilities,
|
||||
}
|
||||
ep2 := &Endpoint{
|
||||
linkAddr: linkAddr2,
|
||||
linked: ep1,
|
||||
capabilities: capabilities,
|
||||
}
|
||||
ep1.linked = ep2
|
||||
return ep1, ep2
|
||||
}
|
||||
|
||||
// Endpoint is one end of a pipe.
|
||||
type Endpoint struct {
|
||||
capabilities stack.LinkEndpointCapabilities
|
||||
linkAddr tcpip.LinkAddress
|
||||
dispatcher stack.NetworkDispatcher
|
||||
linked *Endpoint
|
||||
onWritePacket func(*stack.PacketBuffer)
|
||||
}
|
||||
|
||||
// WritePacket implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) WritePacket(r *stack.Route, _ *stack.GSO, proto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
if !e.linked.IsAttached() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// The pipe endpoint will accept all multicast/broadcast link traffic and only
|
||||
// unicast traffic destined to itself.
|
||||
if len(e.linked.linkAddr) != 0 &&
|
||||
r.RemoteLinkAddress != e.linked.linkAddr &&
|
||||
r.RemoteLinkAddress != header.EthernetBroadcastAddress &&
|
||||
!header.IsMulticastEthernetAddress(r.RemoteLinkAddress) {
|
||||
return nil
|
||||
}
|
||||
|
||||
e.linked.dispatcher.DeliverNetworkPacket(e.linkAddr, r.RemoteLinkAddress, proto, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: buffer.NewVectorisedView(pkt.Size(), pkt.Views()),
|
||||
}))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WritePackets implements stack.LinkEndpoint.
|
||||
func (*Endpoint) WritePackets(*stack.Route, *stack.GSO, stack.PacketBufferList, tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// WriteRawPacket implements stack.LinkEndpoint.
|
||||
func (*Endpoint) WriteRawPacket(buffer.VectorisedView) *tcpip.Error {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Attach implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
e.dispatcher = dispatcher
|
||||
}
|
||||
|
||||
// IsAttached implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) IsAttached() bool {
|
||||
return e.dispatcher != nil
|
||||
}
|
||||
|
||||
// Wait implements stack.LinkEndpoint.
|
||||
func (*Endpoint) Wait() {}
|
||||
|
||||
// MTU implements stack.LinkEndpoint.
|
||||
func (*Endpoint) MTU() uint32 {
|
||||
return header.IPv6MinimumMTU
|
||||
}
|
||||
|
||||
// Capabilities implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities {
|
||||
return e.capabilities
|
||||
}
|
||||
|
||||
// MaxHeaderLength implements stack.LinkEndpoint.
|
||||
func (*Endpoint) MaxHeaderLength() uint16 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// LinkAddress implements stack.LinkEndpoint.
|
||||
func (e *Endpoint) LinkAddress() tcpip.LinkAddress {
|
||||
return e.linkAddr
|
||||
}
|
||||
|
||||
// ARPHardwareType implements stack.LinkEndpoint.
|
||||
func (*Endpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareEther
|
||||
}
|
||||
|
||||
// AddHeader implements stack.LinkEndpoint.
|
||||
func (*Endpoint) AddHeader(_, _ tcpip.LinkAddress, _ tcpip.NetworkProtocolNumber, _ *stack.PacketBuffer) {
|
||||
}
|
||||
@@ -76,13 +76,29 @@ func (d *Device) Release(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// NICID returns the NIC ID of the device.
|
||||
//
|
||||
// Must only be called after the device has been attached to an endpoint.
|
||||
func (d *Device) NICID() tcpip.NICID {
|
||||
d.mu.RLock()
|
||||
defer d.mu.RUnlock()
|
||||
|
||||
if d.endpoint == nil {
|
||||
panic("called NICID on a device that has not been attached")
|
||||
}
|
||||
|
||||
return d.endpoint.nicID
|
||||
}
|
||||
|
||||
// SetIff services TUNSETIFF ioctl(2) request.
|
||||
func (d *Device) SetIff(s *stack.Stack, name string, flags uint16) error {
|
||||
//
|
||||
// Returns true if a new NIC was created; false if an existing one was attached.
|
||||
func (d *Device) SetIff(s *stack.Stack, name string, flags uint16) (bool, error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if d.endpoint != nil {
|
||||
return syserror.EINVAL
|
||||
return false, syserror.EINVAL
|
||||
}
|
||||
|
||||
// Input validations.
|
||||
@@ -90,7 +106,7 @@ func (d *Device) SetIff(s *stack.Stack, name string, flags uint16) error {
|
||||
isTap := flags&linux.IFF_TAP != 0
|
||||
supportedFlags := uint16(linux.IFF_TUN | linux.IFF_TAP | linux.IFF_NO_PI)
|
||||
if isTap && isTun || !isTap && !isTun || flags&^supportedFlags != 0 {
|
||||
return syserror.EINVAL
|
||||
return false, syserror.EINVAL
|
||||
}
|
||||
|
||||
prefix := "tun"
|
||||
@@ -103,32 +119,32 @@ func (d *Device) SetIff(s *stack.Stack, name string, flags uint16) error {
|
||||
linkCaps |= stack.CapabilityResolutionRequired
|
||||
}
|
||||
|
||||
endpoint, err := attachOrCreateNIC(s, name, prefix, linkCaps)
|
||||
endpoint, created, err := attachOrCreateNIC(s, name, prefix, linkCaps)
|
||||
if err != nil {
|
||||
return syserror.EINVAL
|
||||
return false, syserror.EINVAL
|
||||
}
|
||||
|
||||
d.endpoint = endpoint
|
||||
d.notifyHandle = d.endpoint.AddNotify(d)
|
||||
d.flags = flags
|
||||
return nil
|
||||
return created, nil
|
||||
}
|
||||
|
||||
func attachOrCreateNIC(s *stack.Stack, name, prefix string, linkCaps stack.LinkEndpointCapabilities) (*tunEndpoint, error) {
|
||||
func attachOrCreateNIC(s *stack.Stack, name, prefix string, linkCaps stack.LinkEndpointCapabilities) (*tunEndpoint, bool, error) {
|
||||
for {
|
||||
// 1. Try to attach to an existing NIC.
|
||||
if name != "" {
|
||||
if nic, found := s.GetNICByName(name); found {
|
||||
endpoint, ok := nic.LinkEndpoint().(*tunEndpoint)
|
||||
if linkEP := s.GetLinkEndpointByName(name); linkEP != nil {
|
||||
endpoint, ok := linkEP.(*tunEndpoint)
|
||||
if !ok {
|
||||
// Not a NIC created by tun device.
|
||||
return nil, syserror.EOPNOTSUPP
|
||||
return nil, false, syserror.EOPNOTSUPP
|
||||
}
|
||||
if !endpoint.TryIncRef() {
|
||||
// Race detected: NIC got deleted in between.
|
||||
continue
|
||||
}
|
||||
return endpoint, nil
|
||||
return endpoint, false, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,12 +167,12 @@ func attachOrCreateNIC(s *stack.Stack, name, prefix string, linkCaps stack.LinkE
|
||||
})
|
||||
switch err {
|
||||
case nil:
|
||||
return endpoint, nil
|
||||
return endpoint, true, nil
|
||||
case tcpip.ErrDuplicateNICID:
|
||||
// Race detected: A NIC has been created in between.
|
||||
continue
|
||||
default:
|
||||
return nil, syserror.EINVAL
|
||||
return nil, false, syserror.EINVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ type endpoint struct {
|
||||
enabled uint32
|
||||
|
||||
nic stack.NetworkInterface
|
||||
linkEP stack.LinkEndpoint
|
||||
linkAddrCache stack.LinkAddressCache
|
||||
nud stack.NUDHandler
|
||||
}
|
||||
@@ -92,12 +91,12 @@ func (e *endpoint) DefaultTTL() uint8 {
|
||||
}
|
||||
|
||||
func (e *endpoint) MTU() uint32 {
|
||||
lmtu := e.linkEP.MTU()
|
||||
lmtu := e.nic.MTU()
|
||||
return lmtu - uint32(e.MaxHeaderLength())
|
||||
}
|
||||
|
||||
func (e *endpoint) MaxHeaderLength() uint16 {
|
||||
return e.linkEP.MaxHeaderLength() + header.ARPSize
|
||||
return e.nic.MaxHeaderLength() + header.ARPSize
|
||||
}
|
||||
|
||||
func (e *endpoint) Close() {
|
||||
@@ -154,17 +153,25 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
e.nud.HandleProbe(remoteAddr, localAddr, ProtocolNumber, remoteLinkAddr, e.protocol)
|
||||
}
|
||||
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(e.linkEP.MaxHeaderLength()) + header.ARPSize,
|
||||
// As per RFC 826, under Packet Reception:
|
||||
// Swap hardware and protocol fields, putting the local hardware and
|
||||
// protocol addresses in the sender fields.
|
||||
//
|
||||
// Send the packet to the (new) target hardware address on the same
|
||||
// hardware on which the request was received.
|
||||
origSender := h.HardwareAddressSender()
|
||||
r.RemoteLinkAddress = tcpip.LinkAddress(origSender)
|
||||
respPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(e.nic.MaxHeaderLength()) + header.ARPSize,
|
||||
})
|
||||
packet := header.ARP(pkt.NetworkHeader().Push(header.ARPSize))
|
||||
packet := header.ARP(respPkt.NetworkHeader().Push(header.ARPSize))
|
||||
packet.SetIPv4OverEthernet()
|
||||
packet.SetOp(header.ARPReply)
|
||||
copy(packet.HardwareAddressSender(), r.LocalLinkAddress[:])
|
||||
copy(packet.ProtocolAddressSender(), h.ProtocolAddressTarget())
|
||||
copy(packet.HardwareAddressTarget(), h.HardwareAddressSender())
|
||||
copy(packet.HardwareAddressTarget(), origSender)
|
||||
copy(packet.ProtocolAddressTarget(), h.ProtocolAddressSender())
|
||||
_ = e.linkEP.WritePacket(r, nil /* gso */, ProtocolNumber, pkt)
|
||||
_ = e.nic.WritePacket(r, nil /* gso */, ProtocolNumber, respPkt)
|
||||
|
||||
case header.ARPReply:
|
||||
addr := tcpip.Address(h.ProtocolAddressSender())
|
||||
@@ -207,7 +214,6 @@ func (p *protocol) NewEndpoint(nic stack.NetworkInterface, linkAddrCache stack.L
|
||||
e := &endpoint{
|
||||
protocol: p,
|
||||
nic: nic,
|
||||
linkEP: nic.LinkEndpoint(),
|
||||
linkAddrCache: linkAddrCache,
|
||||
nud: nud,
|
||||
}
|
||||
@@ -223,6 +229,7 @@ func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
|
||||
// LinkAddressRequest implements stack.LinkAddressResolver.LinkAddressRequest.
|
||||
func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, linkEP stack.LinkEndpoint) *tcpip.Error {
|
||||
r := &stack.Route{
|
||||
NetProto: ProtocolNumber,
|
||||
RemoteLinkAddress: remoteLinkAddr,
|
||||
}
|
||||
if len(r.RemoteLinkAddress) == 0 {
|
||||
|
||||
@@ -270,7 +270,7 @@ func buildDummyStack(t *testing.T) *stack.Stack {
|
||||
var _ stack.NetworkInterface = (*testInterface)(nil)
|
||||
|
||||
type testInterface struct {
|
||||
tester testObject
|
||||
testObject
|
||||
|
||||
mu struct {
|
||||
sync.RWMutex
|
||||
@@ -302,10 +302,6 @@ func (t *testInterface) setEnabled(v bool) {
|
||||
t.mu.disabled = !v
|
||||
}
|
||||
|
||||
func (t *testInterface) LinkEndpoint() stack.LinkEndpoint {
|
||||
return &t.tester
|
||||
}
|
||||
|
||||
func TestSourceAddressValidation(t *testing.T) {
|
||||
rxIPv4ICMP := func(e *channel.Endpoint, src tcpip.Address) {
|
||||
totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize
|
||||
@@ -517,7 +513,7 @@ func TestIPv4Send(t *testing.T) {
|
||||
s := buildDummyStack(t)
|
||||
proto := s.NetworkProtocolInstance(ipv4.ProtocolNumber)
|
||||
nic := testInterface{
|
||||
tester: testObject{
|
||||
testObject: testObject{
|
||||
t: t,
|
||||
v4: true,
|
||||
},
|
||||
@@ -538,10 +534,10 @@ func TestIPv4Send(t *testing.T) {
|
||||
})
|
||||
|
||||
// Issue the write.
|
||||
nic.tester.protocol = 123
|
||||
nic.tester.srcAddr = localIPv4Addr
|
||||
nic.tester.dstAddr = remoteIPv4Addr
|
||||
nic.tester.contents = payload
|
||||
nic.testObject.protocol = 123
|
||||
nic.testObject.srcAddr = localIPv4Addr
|
||||
nic.testObject.dstAddr = remoteIPv4Addr
|
||||
nic.testObject.contents = payload
|
||||
|
||||
r, err := buildIPv4Route(localIPv4Addr, remoteIPv4Addr)
|
||||
if err != nil {
|
||||
@@ -560,12 +556,12 @@ func TestIPv4Receive(t *testing.T) {
|
||||
s := buildDummyStack(t)
|
||||
proto := s.NetworkProtocolInstance(ipv4.ProtocolNumber)
|
||||
nic := testInterface{
|
||||
tester: testObject{
|
||||
testObject: testObject{
|
||||
t: t,
|
||||
v4: true,
|
||||
},
|
||||
}
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.tester)
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.testObject)
|
||||
defer ep.Close()
|
||||
|
||||
if err := ep.Enable(); err != nil {
|
||||
@@ -590,10 +586,10 @@ func TestIPv4Receive(t *testing.T) {
|
||||
}
|
||||
|
||||
// Give packet to ipv4 endpoint, dispatcher will validate that it's ok.
|
||||
nic.tester.protocol = 10
|
||||
nic.tester.srcAddr = remoteIPv4Addr
|
||||
nic.tester.dstAddr = localIPv4Addr
|
||||
nic.tester.contents = view[header.IPv4MinimumSize:totalLen]
|
||||
nic.testObject.protocol = 10
|
||||
nic.testObject.srcAddr = remoteIPv4Addr
|
||||
nic.testObject.dstAddr = localIPv4Addr
|
||||
nic.testObject.contents = view[header.IPv4MinimumSize:totalLen]
|
||||
|
||||
r, err := buildIPv4Route(localIPv4Addr, remoteIPv4Addr)
|
||||
if err != nil {
|
||||
@@ -606,8 +602,8 @@ func TestIPv4Receive(t *testing.T) {
|
||||
t.Fatalf("failed to parse packet: %x", pkt.Data.ToView())
|
||||
}
|
||||
ep.HandlePacket(&r, pkt)
|
||||
if nic.tester.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.tester.dataCalls)
|
||||
if nic.testObject.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.testObject.dataCalls)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,11 +636,11 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
s := buildDummyStack(t)
|
||||
proto := s.NetworkProtocolInstance(ipv4.ProtocolNumber)
|
||||
nic := testInterface{
|
||||
tester: testObject{
|
||||
testObject: testObject{
|
||||
t: t,
|
||||
},
|
||||
}
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.tester)
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.testObject)
|
||||
defer ep.Close()
|
||||
|
||||
if err := ep.Enable(); err != nil {
|
||||
@@ -691,16 +687,16 @@ func TestIPv4ReceiveControl(t *testing.T) {
|
||||
|
||||
// Give packet to IPv4 endpoint, dispatcher will validate that
|
||||
// it's ok.
|
||||
nic.tester.protocol = 10
|
||||
nic.tester.srcAddr = remoteIPv4Addr
|
||||
nic.tester.dstAddr = localIPv4Addr
|
||||
nic.tester.contents = view[dataOffset:]
|
||||
nic.tester.typ = c.expectedTyp
|
||||
nic.tester.extra = c.expectedExtra
|
||||
nic.testObject.protocol = 10
|
||||
nic.testObject.srcAddr = remoteIPv4Addr
|
||||
nic.testObject.dstAddr = localIPv4Addr
|
||||
nic.testObject.contents = view[dataOffset:]
|
||||
nic.testObject.typ = c.expectedTyp
|
||||
nic.testObject.extra = c.expectedExtra
|
||||
|
||||
ep.HandlePacket(&r, truncatedPacket(view, c.trunc, header.IPv4MinimumSize))
|
||||
if want := c.expectedCount; nic.tester.controlCalls != want {
|
||||
t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, nic.tester.controlCalls, want)
|
||||
if want := c.expectedCount; nic.testObject.controlCalls != want {
|
||||
t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, nic.testObject.controlCalls, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -710,12 +706,12 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
s := buildDummyStack(t)
|
||||
proto := s.NetworkProtocolInstance(ipv4.ProtocolNumber)
|
||||
nic := testInterface{
|
||||
tester: testObject{
|
||||
testObject: testObject{
|
||||
t: t,
|
||||
v4: true,
|
||||
},
|
||||
}
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.tester)
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.testObject)
|
||||
defer ep.Close()
|
||||
|
||||
if err := ep.Enable(); err != nil {
|
||||
@@ -758,10 +754,10 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
}
|
||||
|
||||
// Give packet to ipv4 endpoint, dispatcher will validate that it's ok.
|
||||
nic.tester.protocol = 10
|
||||
nic.tester.srcAddr = remoteIPv4Addr
|
||||
nic.tester.dstAddr = localIPv4Addr
|
||||
nic.tester.contents = append(frag1[header.IPv4MinimumSize:totalLen], frag2[header.IPv4MinimumSize:totalLen]...)
|
||||
nic.testObject.protocol = 10
|
||||
nic.testObject.srcAddr = remoteIPv4Addr
|
||||
nic.testObject.dstAddr = localIPv4Addr
|
||||
nic.testObject.contents = append(frag1[header.IPv4MinimumSize:totalLen], frag2[header.IPv4MinimumSize:totalLen]...)
|
||||
|
||||
r, err := buildIPv4Route(localIPv4Addr, remoteIPv4Addr)
|
||||
if err != nil {
|
||||
@@ -776,8 +772,8 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
t.Fatalf("failed to parse packet: %x", pkt.Data.ToView())
|
||||
}
|
||||
ep.HandlePacket(&r, pkt)
|
||||
if nic.tester.dataCalls != 0 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 0", nic.tester.dataCalls)
|
||||
if nic.testObject.dataCalls != 0 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 0", nic.testObject.dataCalls)
|
||||
}
|
||||
|
||||
// Send second segment.
|
||||
@@ -788,8 +784,8 @@ func TestIPv4FragmentationReceive(t *testing.T) {
|
||||
t.Fatalf("failed to parse packet: %x", pkt.Data.ToView())
|
||||
}
|
||||
ep.HandlePacket(&r, pkt)
|
||||
if nic.tester.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.tester.dataCalls)
|
||||
if nic.testObject.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.testObject.dataCalls)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +793,7 @@ func TestIPv6Send(t *testing.T) {
|
||||
s := buildDummyStack(t)
|
||||
proto := s.NetworkProtocolInstance(ipv6.ProtocolNumber)
|
||||
nic := testInterface{
|
||||
tester: testObject{
|
||||
testObject: testObject{
|
||||
t: t,
|
||||
},
|
||||
}
|
||||
@@ -821,10 +817,10 @@ func TestIPv6Send(t *testing.T) {
|
||||
})
|
||||
|
||||
// Issue the write.
|
||||
nic.tester.protocol = 123
|
||||
nic.tester.srcAddr = localIPv6Addr
|
||||
nic.tester.dstAddr = remoteIPv6Addr
|
||||
nic.tester.contents = payload
|
||||
nic.testObject.protocol = 123
|
||||
nic.testObject.srcAddr = localIPv6Addr
|
||||
nic.testObject.dstAddr = remoteIPv6Addr
|
||||
nic.testObject.contents = payload
|
||||
|
||||
r, err := buildIPv6Route(localIPv6Addr, remoteIPv6Addr)
|
||||
if err != nil {
|
||||
@@ -843,11 +839,11 @@ func TestIPv6Receive(t *testing.T) {
|
||||
s := buildDummyStack(t)
|
||||
proto := s.NetworkProtocolInstance(ipv6.ProtocolNumber)
|
||||
nic := testInterface{
|
||||
tester: testObject{
|
||||
testObject: testObject{
|
||||
t: t,
|
||||
},
|
||||
}
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.tester)
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.testObject)
|
||||
defer ep.Close()
|
||||
|
||||
if err := ep.Enable(); err != nil {
|
||||
@@ -871,10 +867,10 @@ func TestIPv6Receive(t *testing.T) {
|
||||
}
|
||||
|
||||
// Give packet to ipv6 endpoint, dispatcher will validate that it's ok.
|
||||
nic.tester.protocol = 10
|
||||
nic.tester.srcAddr = remoteIPv6Addr
|
||||
nic.tester.dstAddr = localIPv6Addr
|
||||
nic.tester.contents = view[header.IPv6MinimumSize:totalLen]
|
||||
nic.testObject.protocol = 10
|
||||
nic.testObject.srcAddr = remoteIPv6Addr
|
||||
nic.testObject.dstAddr = localIPv6Addr
|
||||
nic.testObject.contents = view[header.IPv6MinimumSize:totalLen]
|
||||
|
||||
r, err := buildIPv6Route(localIPv6Addr, remoteIPv6Addr)
|
||||
if err != nil {
|
||||
@@ -888,8 +884,8 @@ func TestIPv6Receive(t *testing.T) {
|
||||
t.Fatalf("failed to parse packet: %x", pkt.Data.ToView())
|
||||
}
|
||||
ep.HandlePacket(&r, pkt)
|
||||
if nic.tester.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.tester.dataCalls)
|
||||
if nic.testObject.dataCalls != 1 {
|
||||
t.Fatalf("Bad number of data calls: got %x, want 1", nic.testObject.dataCalls)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -931,11 +927,11 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
s := buildDummyStack(t)
|
||||
proto := s.NetworkProtocolInstance(ipv6.ProtocolNumber)
|
||||
nic := testInterface{
|
||||
tester: testObject{
|
||||
testObject: testObject{
|
||||
t: t,
|
||||
},
|
||||
}
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.tester)
|
||||
ep := proto.NewEndpoint(&nic, nil, nil, &nic.testObject)
|
||||
defer ep.Close()
|
||||
|
||||
if err := ep.Enable(); err != nil {
|
||||
@@ -994,19 +990,19 @@ func TestIPv6ReceiveControl(t *testing.T) {
|
||||
|
||||
// Give packet to IPv6 endpoint, dispatcher will validate that
|
||||
// it's ok.
|
||||
nic.tester.protocol = 10
|
||||
nic.tester.srcAddr = remoteIPv6Addr
|
||||
nic.tester.dstAddr = localIPv6Addr
|
||||
nic.tester.contents = view[dataOffset:]
|
||||
nic.tester.typ = c.expectedTyp
|
||||
nic.tester.extra = c.expectedExtra
|
||||
nic.testObject.protocol = 10
|
||||
nic.testObject.srcAddr = remoteIPv6Addr
|
||||
nic.testObject.dstAddr = localIPv6Addr
|
||||
nic.testObject.contents = view[dataOffset:]
|
||||
nic.testObject.typ = c.expectedTyp
|
||||
nic.testObject.extra = c.expectedExtra
|
||||
|
||||
// Set ICMPv6 checksum.
|
||||
icmp.SetChecksum(header.ICMPv6Checksum(icmp, outerSrcAddr, localIPv6Addr, buffer.VectorisedView{}))
|
||||
|
||||
ep.HandlePacket(&r, truncatedPacket(view, c.trunc, header.IPv6MinimumSize))
|
||||
if want := c.expectedCount; nic.tester.controlCalls != want {
|
||||
t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, nic.tester.controlCalls, want)
|
||||
if want := c.expectedCount; nic.testObject.controlCalls != want {
|
||||
t.Fatalf("Bad number of control calls for %q case: got %v, want %v", c.name, nic.testObject.controlCalls, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ go_test(
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/link/channel",
|
||||
"//pkg/tcpip/link/sniffer",
|
||||
"//pkg/tcpip/network/arp",
|
||||
"//pkg/tcpip/network/ipv4",
|
||||
"//pkg/tcpip/network/testutil",
|
||||
"//pkg/tcpip/stack",
|
||||
|
||||
@@ -102,8 +102,6 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
|
||||
e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, pkt)
|
||||
|
||||
remoteLinkAddr := r.RemoteLinkAddress
|
||||
|
||||
// As per RFC 1122 section 3.2.1.3, when a host sends any datagram, the IP
|
||||
// source address MUST be one of its own IP addresses (but not a broadcast
|
||||
// or multicast address).
|
||||
@@ -119,9 +117,6 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
}
|
||||
defer r.Release()
|
||||
|
||||
// Use the remote link address from the incoming packet.
|
||||
r.ResolveWith(remoteLinkAddr)
|
||||
|
||||
// TODO(gvisor.dev/issue/3810:) When adding protocol numbers into the
|
||||
// header information, we may have to change this code to handle the
|
||||
// ICMP header no longer being in the data buffer.
|
||||
@@ -244,13 +239,7 @@ func (*icmpReasonProtoUnreachable) isICMPReason() {}
|
||||
// the problematic packet. It incorporates as much of that packet as
|
||||
// possible as well as any error metadata as is available. returnError
|
||||
// expects pkt to hold a valid IPv4 packet as per the wire format.
|
||||
func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
sent := r.Stats().ICMP.V4PacketsSent
|
||||
if !r.Stack().AllowICMPMessage() {
|
||||
sent.RateLimited.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
// We check we are responding only when we are allowed to.
|
||||
// See RFC 1812 section 4.3.2.7 (shown below).
|
||||
//
|
||||
@@ -279,6 +268,25 @@ func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tc
|
||||
return nil
|
||||
}
|
||||
|
||||
// Even if we were able to receive a packet from some remote, we may not have
|
||||
// a route to it - the remote may be blocked via routing rules. We must always
|
||||
// consult our routing table and find a route to the remote before sending any
|
||||
// packet.
|
||||
route, err := p.stack.FindRoute(r.NICID(), r.LocalAddress, r.RemoteAddress, ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer route.Release()
|
||||
// From this point on, the incoming route should no longer be used; route
|
||||
// must be used to send the ICMP error.
|
||||
r = nil
|
||||
|
||||
sent := p.stack.Stats().ICMP.V4PacketsSent
|
||||
if !p.stack.AllowICMPMessage() {
|
||||
sent.RateLimited.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
networkHeader := pkt.NetworkHeader().View()
|
||||
transportHeader := pkt.TransportHeader().View()
|
||||
|
||||
@@ -329,11 +337,11 @@ func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tc
|
||||
// least 8 bytes of the payload must be included. Today linux and other
|
||||
// systems implement the RFC 1812 definition and not the original
|
||||
// requirement. We treat 8 bytes as the minimum but will try send more.
|
||||
mtu := int(r.MTU())
|
||||
mtu := int(route.MTU())
|
||||
if mtu > header.IPv4MinimumProcessableDatagramSize {
|
||||
mtu = header.IPv4MinimumProcessableDatagramSize
|
||||
}
|
||||
headerLen := int(r.MaxHeaderLength()) + header.ICMPv4MinimumSize
|
||||
headerLen := int(route.MaxHeaderLength()) + header.ICMPv4MinimumSize
|
||||
available := int(mtu) - headerLen
|
||||
|
||||
if available < header.IPv4MinimumSize+header.ICMPv4MinimumErrorPayloadSize {
|
||||
@@ -378,11 +386,11 @@ func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tc
|
||||
icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data))
|
||||
counter := sent.DstUnreachable
|
||||
|
||||
if err := r.WritePacket(
|
||||
if err := route.WritePacket(
|
||||
nil, /* gso */
|
||||
stack.NetworkHeaderParams{
|
||||
Protocol: header.ICMPv4ProtocolNumber,
|
||||
TTL: r.DefaultTTL(),
|
||||
TTL: route.DefaultTTL(),
|
||||
TOS: stack.DefaultTOS,
|
||||
},
|
||||
icmpPkt,
|
||||
|
||||
@@ -66,7 +66,6 @@ var _ stack.NetworkEndpoint = (*endpoint)(nil)
|
||||
|
||||
type endpoint struct {
|
||||
nic stack.NetworkInterface
|
||||
linkEP stack.LinkEndpoint
|
||||
dispatcher stack.TransportDispatcher
|
||||
protocol *protocol
|
||||
|
||||
@@ -87,7 +86,6 @@ type endpoint struct {
|
||||
func (p *protocol) NewEndpoint(nic stack.NetworkInterface, _ stack.LinkAddressCache, _ stack.NUDHandler, dispatcher stack.TransportDispatcher) stack.NetworkEndpoint {
|
||||
e := &endpoint{
|
||||
nic: nic,
|
||||
linkEP: nic.LinkEndpoint(),
|
||||
dispatcher: dispatcher,
|
||||
protocol: p,
|
||||
}
|
||||
@@ -178,18 +176,18 @@ 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.linkEP.MTU())
|
||||
return calculateMTU(e.nic.MTU())
|
||||
}
|
||||
|
||||
// MaxHeaderLength returns the maximum length needed by ipv4 headers (and
|
||||
// underlying protocols).
|
||||
func (e *endpoint) MaxHeaderLength() uint16 {
|
||||
return e.linkEP.MaxHeaderLength() + header.IPv4MaximumHeaderSize
|
||||
return e.nic.MaxHeaderLength() + header.IPv4MaximumHeaderSize
|
||||
}
|
||||
|
||||
// GSOMaxSize returns the maximum GSO packet size.
|
||||
func (e *endpoint) GSOMaxSize() uint32 {
|
||||
if gso, ok := e.linkEP.(stack.GSOEndpoint); ok {
|
||||
if gso, ok := e.nic.(stack.GSOEndpoint); ok {
|
||||
return gso.GSOMaxSize()
|
||||
}
|
||||
return 0
|
||||
@@ -210,7 +208,7 @@ func (e *endpoint) writePacketFragments(r *stack.Route, gso *stack.GSO, mtu uint
|
||||
|
||||
for {
|
||||
fragPkt, more := buildNextFragment(&pf, networkHeader)
|
||||
if err := e.linkEP.WritePacket(r, gso, ProtocolNumber, fragPkt); err != nil {
|
||||
if err := e.nic.WritePacket(r, gso, ProtocolNumber, fragPkt); err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(pf.RemainingFragmentCount() + 1))
|
||||
return err
|
||||
}
|
||||
@@ -283,10 +281,10 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, params stack.Netw
|
||||
if r.Loop&stack.PacketOut == 0 {
|
||||
return nil
|
||||
}
|
||||
if pkt.Size() > int(e.linkEP.MTU()) && (gso == nil || gso.Type == stack.GSONone) {
|
||||
return e.writePacketFragments(r, gso, e.linkEP.MTU(), pkt)
|
||||
if pkt.Size() > int(e.nic.MTU()) && (gso == nil || gso.Type == stack.GSONone) {
|
||||
return e.writePacketFragments(r, gso, e.nic.MTU(), pkt)
|
||||
}
|
||||
if err := e.linkEP.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
if err := e.nic.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
return err
|
||||
}
|
||||
@@ -316,7 +314,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
if len(dropped) == 0 && len(natPkts) == 0 {
|
||||
// Fast path: If no packets are to be dropped then we can just invoke the
|
||||
// faster WritePackets API directly.
|
||||
n, err := e.linkEP.WritePackets(r, gso, pkts, ProtocolNumber)
|
||||
n, err := e.nic.WritePackets(r, gso, pkts, ProtocolNumber)
|
||||
r.Stats().IP.PacketsSent.IncrementBy(uint64(n))
|
||||
if err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(pkts.Len() - n))
|
||||
@@ -343,7 +341,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err := e.linkEP.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
if err := e.nic.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
r.Stats().IP.PacketsSent.IncrementBy(uint64(n))
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(pkts.Len() - n - len(dropped)))
|
||||
// Dropped packets aren't errors, so include them in
|
||||
@@ -404,7 +402,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := e.linkEP.WritePacket(r, nil /* gso */, ProtocolNumber, pkt); err != nil {
|
||||
if err := e.nic.WritePacket(r, nil /* gso */, ProtocolNumber, pkt); err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
return err
|
||||
}
|
||||
@@ -512,13 +510,13 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// 3 (Port Unreachable), when the designated transport protocol
|
||||
// (e.g., UDP) is unable to demultiplex the datagram but has no
|
||||
// protocol mechanism to inform the sender.
|
||||
_ = returnError(r, &icmpReasonPortUnreachable{}, pkt)
|
||||
_ = e.protocol.returnError(r, &icmpReasonPortUnreachable{}, pkt)
|
||||
case stack.TransportPacketProtocolUnreachable:
|
||||
// As per RFC: 1122 Section 3.2.2.1
|
||||
// A host SHOULD generate Destination Unreachable messages with code:
|
||||
// 2 (Protocol Unreachable), when the designated transport protocol
|
||||
// is not supported
|
||||
_ = returnError(r, &icmpReasonProtoUnreachable{}, pkt)
|
||||
_ = e.protocol.returnError(r, &icmpReasonProtoUnreachable{}, pkt)
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized result from DeliverTransportPacket = %d", res))
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package ipv4_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"net"
|
||||
@@ -28,6 +29,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/sniffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/arp"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/testutil"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
@@ -1492,3 +1494,204 @@ func (lm *limitedMatcher) Match(stack.Hook, *stack.PacketBuffer, string) (bool,
|
||||
lm.limit--
|
||||
return false, false
|
||||
}
|
||||
|
||||
func TestPacketQueing(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
var (
|
||||
host1NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06")
|
||||
host2NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09")
|
||||
|
||||
host1IPv4Addr = tcpip.ProtocolAddress{
|
||||
Protocol: ipv4.ProtocolNumber,
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: tcpip.Address(net.ParseIP("192.168.0.1").To4()),
|
||||
PrefixLen: 24,
|
||||
},
|
||||
}
|
||||
host2IPv4Addr = tcpip.ProtocolAddress{
|
||||
Protocol: ipv4.ProtocolNumber,
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: tcpip.Address(net.ParseIP("192.168.0.2").To4()),
|
||||
PrefixLen: 8,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
rxPkt func(*channel.Endpoint)
|
||||
checkResp func(*testing.T, *channel.Endpoint)
|
||||
}{
|
||||
{
|
||||
name: "ICMP Error",
|
||||
rxPkt: func(e *channel.Endpoint) {
|
||||
hdr := buffer.NewPrependable(header.IPv4MinimumSize + header.UDPMinimumSize)
|
||||
u := header.UDP(hdr.Prepend(header.UDPMinimumSize))
|
||||
u.Encode(&header.UDPFields{
|
||||
SrcPort: 5555,
|
||||
DstPort: 80,
|
||||
Length: header.UDPMinimumSize,
|
||||
})
|
||||
sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv4Addr.AddressWithPrefix.Address, host1IPv4Addr.AddressWithPrefix.Address, header.UDPMinimumSize)
|
||||
sum = header.Checksum(header.UDP([]byte{}), sum)
|
||||
u.SetChecksum(^u.CalculateChecksum(sum))
|
||||
ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
|
||||
ip.Encode(&header.IPv4Fields{
|
||||
IHL: header.IPv4MinimumSize,
|
||||
TotalLength: header.IPv4MinimumSize + header.UDPMinimumSize,
|
||||
TTL: ipv4.DefaultTTL,
|
||||
Protocol: uint8(udp.ProtocolNumber),
|
||||
SrcAddr: host2IPv4Addr.AddressWithPrefix.Address,
|
||||
DstAddr: host1IPv4Addr.AddressWithPrefix.Address,
|
||||
})
|
||||
e.InjectInbound(ipv4.ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
}))
|
||||
},
|
||||
checkResp: func(t *testing.T, e *channel.Endpoint) {
|
||||
p, ok := e.ReadContext(context.Background())
|
||||
if !ok {
|
||||
t.Fatalf("timed out waiting for packet")
|
||||
}
|
||||
if p.Proto != header.IPv4ProtocolNumber {
|
||||
t.Errorf("got p.Proto = %d, want = %d", p.Proto, header.IPv4ProtocolNumber)
|
||||
}
|
||||
if p.Route.RemoteLinkAddress != host2NICLinkAddr {
|
||||
t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, host2NICLinkAddr)
|
||||
}
|
||||
checker.IPv4(t, stack.PayloadSince(p.Pkt.NetworkHeader()),
|
||||
checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address),
|
||||
checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address),
|
||||
checker.ICMPv4(
|
||||
checker.ICMPv4Type(header.ICMPv4DstUnreachable),
|
||||
checker.ICMPv4Code(header.ICMPv4PortUnreachable)))
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "Ping",
|
||||
rxPkt: func(e *channel.Endpoint) {
|
||||
totalLen := header.IPv4MinimumSize + header.ICMPv4MinimumSize
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
|
||||
pkt.SetType(header.ICMPv4Echo)
|
||||
pkt.SetCode(0)
|
||||
pkt.SetChecksum(0)
|
||||
pkt.SetChecksum(^header.Checksum(pkt, 0))
|
||||
ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
|
||||
ip.Encode(&header.IPv4Fields{
|
||||
IHL: header.IPv4MinimumSize,
|
||||
TotalLength: uint16(totalLen),
|
||||
Protocol: uint8(icmp.ProtocolNumber4),
|
||||
TTL: ipv4.DefaultTTL,
|
||||
SrcAddr: host2IPv4Addr.AddressWithPrefix.Address,
|
||||
DstAddr: host1IPv4Addr.AddressWithPrefix.Address,
|
||||
})
|
||||
e.InjectInbound(header.IPv4ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
}))
|
||||
},
|
||||
checkResp: func(t *testing.T, e *channel.Endpoint) {
|
||||
p, ok := e.ReadContext(context.Background())
|
||||
if !ok {
|
||||
t.Fatalf("timed out waiting for packet")
|
||||
}
|
||||
if p.Proto != header.IPv4ProtocolNumber {
|
||||
t.Errorf("got p.Proto = %d, want = %d", p.Proto, header.IPv4ProtocolNumber)
|
||||
}
|
||||
if p.Route.RemoteLinkAddress != host2NICLinkAddr {
|
||||
t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, host2NICLinkAddr)
|
||||
}
|
||||
checker.IPv4(t, stack.PayloadSince(p.Pkt.NetworkHeader()),
|
||||
checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address),
|
||||
checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address),
|
||||
checker.ICMPv4(
|
||||
checker.ICMPv4Type(header.ICMPv4EchoReply),
|
||||
checker.ICMPv4Code(header.ICMPv4UnusedCode)))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
e := channel.New(1, header.IPv6MinimumMTU, host1NICLinkAddr)
|
||||
e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
|
||||
})
|
||||
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
|
||||
}
|
||||
if err := s.AddAddress(nicID, arp.ProtocolNumber, arp.ProtocolAddress); err != nil {
|
||||
t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, arp.ProtocolNumber, arp.ProtocolAddress, err)
|
||||
}
|
||||
if err := s.AddProtocolAddress(nicID, host1IPv4Addr); err != nil {
|
||||
t.Fatalf("s.AddProtocolAddress(%d, %#v): %s", nicID, host1IPv4Addr, err)
|
||||
}
|
||||
|
||||
s.SetRouteTable([]tcpip.Route{
|
||||
tcpip.Route{
|
||||
Destination: host1IPv4Addr.AddressWithPrefix.Subnet(),
|
||||
NIC: nicID,
|
||||
},
|
||||
})
|
||||
|
||||
// Receive a packet to trigger link resolution before a response is sent.
|
||||
test.rxPkt(e)
|
||||
|
||||
// Wait for a ARP request since link address resolution should be
|
||||
// performed.
|
||||
{
|
||||
p, ok := e.ReadContext(context.Background())
|
||||
if !ok {
|
||||
t.Fatalf("timed out waiting for packet")
|
||||
}
|
||||
if p.Proto != arp.ProtocolNumber {
|
||||
t.Errorf("got p.Proto = %d, want = %d", p.Proto, arp.ProtocolNumber)
|
||||
}
|
||||
if p.Route.RemoteLinkAddress != header.EthernetBroadcastAddress {
|
||||
t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, header.EthernetBroadcastAddress)
|
||||
}
|
||||
rep := header.ARP(p.Pkt.NetworkHeader().View())
|
||||
if got := rep.Op(); got != header.ARPRequest {
|
||||
t.Errorf("got Op() = %d, want = %d", got, header.ARPRequest)
|
||||
}
|
||||
if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != host1NICLinkAddr {
|
||||
t.Errorf("got HardwareAddressSender = %s, want = %s", got, host1NICLinkAddr)
|
||||
}
|
||||
if got := tcpip.Address(rep.ProtocolAddressSender()); got != host1IPv4Addr.AddressWithPrefix.Address {
|
||||
t.Errorf("got ProtocolAddressSender = %s, want = %s", got, host1IPv4Addr.AddressWithPrefix.Address)
|
||||
}
|
||||
if got := tcpip.Address(rep.ProtocolAddressTarget()); got != host2IPv4Addr.AddressWithPrefix.Address {
|
||||
t.Errorf("got ProtocolAddressTarget = %s, want = %s", got, host2IPv4Addr.AddressWithPrefix.Address)
|
||||
}
|
||||
}
|
||||
|
||||
// Send an ARP reply to complete link address resolution.
|
||||
{
|
||||
hdr := buffer.View(make([]byte, header.ARPSize))
|
||||
packet := header.ARP(hdr)
|
||||
packet.SetIPv4OverEthernet()
|
||||
packet.SetOp(header.ARPReply)
|
||||
copy(packet.HardwareAddressSender(), host2NICLinkAddr)
|
||||
copy(packet.ProtocolAddressSender(), host2IPv4Addr.AddressWithPrefix.Address)
|
||||
copy(packet.HardwareAddressTarget(), host1NICLinkAddr)
|
||||
copy(packet.ProtocolAddressTarget(), host1IPv4Addr.AddressWithPrefix.Address)
|
||||
e.InjectInbound(arp.ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: hdr.ToVectorisedView(),
|
||||
}))
|
||||
}
|
||||
|
||||
// Expect the response now that the link address has resolved.
|
||||
test.checkResp(t, e)
|
||||
|
||||
// Since link resolution was already performed, it shouldn't be performed
|
||||
// again.
|
||||
test.rxPkt(e)
|
||||
test.checkResp(t, e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,8 +440,6 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
return
|
||||
}
|
||||
|
||||
remoteLinkAddr := r.RemoteLinkAddress
|
||||
|
||||
// As per RFC 4291 section 2.7, multicast addresses must not be used as
|
||||
// source addresses in IPv6 packets.
|
||||
localAddr := r.LocalAddress
|
||||
@@ -456,9 +454,6 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
}
|
||||
defer r.Release()
|
||||
|
||||
// Use the link address from the source of the original packet.
|
||||
r.ResolveWith(remoteLinkAddr)
|
||||
|
||||
replyPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(r.MaxHeaderLength()) + header.ICMPv6EchoMinimumSize,
|
||||
Data: pkt.Data,
|
||||
@@ -742,14 +737,7 @@ func (*icmpReasonPortUnreachable) isICMPReason() {}
|
||||
|
||||
// returnError takes an error descriptor and generates the appropriate ICMP
|
||||
// error packet for IPv6 and sends it.
|
||||
func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
stats := r.Stats().ICMP
|
||||
sent := stats.V6PacketsSent
|
||||
if !r.Stack().AllowICMPMessage() {
|
||||
sent.RateLimited.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *protocol) returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
// Only send ICMP error if the address is not a multicast v6
|
||||
// address and the source is not the unspecified address.
|
||||
//
|
||||
@@ -780,6 +768,26 @@ func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tc
|
||||
return nil
|
||||
}
|
||||
|
||||
// Even if we were able to receive a packet from some remote, we may not have
|
||||
// a route to it - the remote may be blocked via routing rules. We must always
|
||||
// consult our routing table and find a route to the remote before sending any
|
||||
// packet.
|
||||
route, err := p.stack.FindRoute(r.NICID(), r.LocalAddress, r.RemoteAddress, ProtocolNumber, false /* multicastLoop */)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer route.Release()
|
||||
// From this point on, the incoming route should no longer be used; route
|
||||
// must be used to send the ICMP error.
|
||||
r = nil
|
||||
|
||||
stats := p.stack.Stats().ICMP
|
||||
sent := stats.V6PacketsSent
|
||||
if !p.stack.AllowICMPMessage() {
|
||||
sent.RateLimited.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
network, transport := pkt.NetworkHeader().View(), pkt.TransportHeader().View()
|
||||
|
||||
if pkt.TransportProtocolNumber == header.ICMPv6ProtocolNumber {
|
||||
@@ -806,11 +814,11 @@ func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tc
|
||||
// packet that caused the error) as possible without making
|
||||
// the error message packet exceed the minimum IPv6 MTU
|
||||
// [IPv6].
|
||||
mtu := int(r.MTU())
|
||||
mtu := int(route.MTU())
|
||||
if mtu > header.IPv6MinimumMTU {
|
||||
mtu = header.IPv6MinimumMTU
|
||||
}
|
||||
headerLen := int(r.MaxHeaderLength()) + header.ICMPv6ErrorHeaderSize
|
||||
headerLen := int(route.MaxHeaderLength()) + header.ICMPv6ErrorHeaderSize
|
||||
available := int(mtu) - headerLen
|
||||
if available < header.IPv6MinimumSize {
|
||||
return nil
|
||||
@@ -843,9 +851,16 @@ func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tc
|
||||
default:
|
||||
panic(fmt.Sprintf("unsupported ICMP type %T", reason))
|
||||
}
|
||||
icmpHdr.SetChecksum(header.ICMPv6Checksum(icmpHdr, r.LocalAddress, r.RemoteAddress, newPkt.Data))
|
||||
err := r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: r.DefaultTTL(), TOS: stack.DefaultTOS}, newPkt)
|
||||
if err != nil {
|
||||
icmpHdr.SetChecksum(header.ICMPv6Checksum(icmpHdr, route.LocalAddress, route.RemoteAddress, newPkt.Data))
|
||||
if err := route.WritePacket(
|
||||
nil, /* gso */
|
||||
stack.NetworkHeaderParams{
|
||||
Protocol: header.ICMPv6ProtocolNumber,
|
||||
TTL: route.DefaultTTL(),
|
||||
TOS: stack.DefaultTOS,
|
||||
},
|
||||
newPkt,
|
||||
); err != nil {
|
||||
sent.Dropped.Increment()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@ package ipv6
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
@@ -28,6 +30,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/sniffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
@@ -40,6 +43,9 @@ const (
|
||||
|
||||
defaultChannelSize = 1
|
||||
defaultMTU = 65536
|
||||
|
||||
// Extra time to use when waiting for an async event to occur.
|
||||
defaultAsyncPositiveEventTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -110,7 +116,9 @@ func (*stubNUDHandler) HandleUpperLevelConfirmation(addr tcpip.Address) {
|
||||
|
||||
var _ stack.NetworkInterface = (*testInterface)(nil)
|
||||
|
||||
type testInterface struct{}
|
||||
type testInterface struct {
|
||||
stack.NetworkLinkEndpoint
|
||||
}
|
||||
|
||||
func (*testInterface) ID() tcpip.NICID {
|
||||
return 0
|
||||
@@ -128,10 +136,6 @@ func (*testInterface) Enabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (*testInterface) LinkEndpoint() stack.LinkEndpoint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestICMPCounts(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1281,3 +1285,210 @@ func TestLinkAddressRequest(t *testing.T) {
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPacketQueing(t *testing.T) {
|
||||
const nicID = 1
|
||||
|
||||
var (
|
||||
host1NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x06")
|
||||
host2NICLinkAddr = tcpip.LinkAddress("\x02\x03\x03\x04\x05\x09")
|
||||
|
||||
host1IPv6Addr = tcpip.ProtocolAddress{
|
||||
Protocol: ProtocolNumber,
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: tcpip.Address(net.ParseIP("a::1").To16()),
|
||||
PrefixLen: 64,
|
||||
},
|
||||
}
|
||||
host2IPv6Addr = tcpip.ProtocolAddress{
|
||||
Protocol: ProtocolNumber,
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: tcpip.Address(net.ParseIP("a::2").To16()),
|
||||
PrefixLen: 64,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
rxPkt func(*channel.Endpoint)
|
||||
checkResp func(*testing.T, *channel.Endpoint)
|
||||
}{
|
||||
{
|
||||
name: "ICMP Error",
|
||||
rxPkt: func(e *channel.Endpoint) {
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.UDPMinimumSize)
|
||||
u := header.UDP(hdr.Prepend(header.UDPMinimumSize))
|
||||
u.Encode(&header.UDPFields{
|
||||
SrcPort: 5555,
|
||||
DstPort: 80,
|
||||
Length: header.UDPMinimumSize,
|
||||
})
|
||||
sum := header.PseudoHeaderChecksum(udp.ProtocolNumber, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, header.UDPMinimumSize)
|
||||
sum = header.Checksum(header.UDP([]byte{}), sum)
|
||||
u.SetChecksum(^u.CalculateChecksum(sum))
|
||||
payloadLength := hdr.UsedLength()
|
||||
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
PayloadLength: uint16(payloadLength),
|
||||
NextHeader: uint8(udp.ProtocolNumber),
|
||||
HopLimit: DefaultTTL,
|
||||
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
|
||||
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
|
||||
})
|
||||
e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
}))
|
||||
},
|
||||
checkResp: func(t *testing.T, e *channel.Endpoint) {
|
||||
p, ok := e.ReadContext(context.Background())
|
||||
if !ok {
|
||||
t.Fatalf("timed out waiting for packet")
|
||||
}
|
||||
if p.Proto != ProtocolNumber {
|
||||
t.Errorf("got p.Proto = %d, want = %d", p.Proto, ProtocolNumber)
|
||||
}
|
||||
if p.Route.RemoteLinkAddress != host2NICLinkAddr {
|
||||
t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, host2NICLinkAddr)
|
||||
}
|
||||
checker.IPv6(t, stack.PayloadSince(p.Pkt.NetworkHeader()),
|
||||
checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address),
|
||||
checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address),
|
||||
checker.ICMPv6(
|
||||
checker.ICMPv6Type(header.ICMPv6DstUnreachable),
|
||||
checker.ICMPv6Code(header.ICMPv6PortUnreachable)))
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "Ping",
|
||||
rxPkt: func(e *channel.Endpoint) {
|
||||
totalLen := header.IPv6MinimumSize + header.ICMPv6MinimumSize
|
||||
hdr := buffer.NewPrependable(totalLen)
|
||||
pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6MinimumSize))
|
||||
pkt.SetType(header.ICMPv6EchoRequest)
|
||||
pkt.SetCode(0)
|
||||
pkt.SetChecksum(0)
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, buffer.VectorisedView{}))
|
||||
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
PayloadLength: header.ICMPv6MinimumSize,
|
||||
NextHeader: uint8(icmp.ProtocolNumber6),
|
||||
HopLimit: DefaultTTL,
|
||||
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
|
||||
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
|
||||
})
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
}))
|
||||
},
|
||||
checkResp: func(t *testing.T, e *channel.Endpoint) {
|
||||
p, ok := e.ReadContext(context.Background())
|
||||
if !ok {
|
||||
t.Fatalf("timed out waiting for packet")
|
||||
}
|
||||
if p.Proto != ProtocolNumber {
|
||||
t.Errorf("got p.Proto = %d, want = %d", p.Proto, ProtocolNumber)
|
||||
}
|
||||
if p.Route.RemoteLinkAddress != host2NICLinkAddr {
|
||||
t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, host2NICLinkAddr)
|
||||
}
|
||||
checker.IPv6(t, stack.PayloadSince(p.Pkt.NetworkHeader()),
|
||||
checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address),
|
||||
checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address),
|
||||
checker.ICMPv6(
|
||||
checker.ICMPv6Type(header.ICMPv6EchoReply),
|
||||
checker.ICMPv6Code(header.ICMPv6UnusedCode)))
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
e := channel.New(1, header.IPv6MinimumMTU, host1NICLinkAddr)
|
||||
e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{udp.NewProtocol},
|
||||
})
|
||||
|
||||
if err := s.CreateNIC(nicID, e); err != nil {
|
||||
t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
|
||||
}
|
||||
if err := s.AddProtocolAddress(nicID, host1IPv6Addr); err != nil {
|
||||
t.Fatalf("s.AddProtocolAddress(%d, %#v): %s", nicID, host1IPv6Addr, err)
|
||||
}
|
||||
|
||||
s.SetRouteTable([]tcpip.Route{
|
||||
tcpip.Route{
|
||||
Destination: host1IPv6Addr.AddressWithPrefix.Subnet(),
|
||||
NIC: nicID,
|
||||
},
|
||||
})
|
||||
|
||||
// Receive a packet to trigger link resolution before a response is sent.
|
||||
test.rxPkt(e)
|
||||
|
||||
// Wait for a neighbor solicitation since link address resolution should
|
||||
// be performed.
|
||||
{
|
||||
p, ok := e.ReadContext(context.Background())
|
||||
if !ok {
|
||||
t.Fatalf("timed out waiting for packet")
|
||||
}
|
||||
if p.Proto != ProtocolNumber {
|
||||
t.Errorf("got Proto = %d, want = %d", p.Proto, ProtocolNumber)
|
||||
}
|
||||
snmc := header.SolicitedNodeAddr(host2IPv6Addr.AddressWithPrefix.Address)
|
||||
if want := header.EthernetAddressFromMulticastIPv6Address(snmc); p.Route.RemoteLinkAddress != want {
|
||||
t.Errorf("got p.Route.RemoteLinkAddress = %s, want = %s", p.Route.RemoteLinkAddress, want)
|
||||
}
|
||||
checker.IPv6(t, stack.PayloadSince(p.Pkt.NetworkHeader()),
|
||||
checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address),
|
||||
checker.DstAddr(snmc),
|
||||
checker.TTL(header.NDPHopLimit),
|
||||
checker.NDPNS(
|
||||
checker.NDPNSTargetAddress(host2IPv6Addr.AddressWithPrefix.Address),
|
||||
checker.NDPNSOptions([]header.NDPOption{header.NDPSourceLinkLayerAddressOption(host1NICLinkAddr)}),
|
||||
))
|
||||
}
|
||||
|
||||
// Send a neighbor advertisement to complete link address resolution.
|
||||
{
|
||||
naSize := header.ICMPv6NeighborAdvertMinimumSize + header.NDPLinkLayerAddressSize
|
||||
hdr := buffer.NewPrependable(header.IPv6MinimumSize + naSize)
|
||||
pkt := header.ICMPv6(hdr.Prepend(naSize))
|
||||
pkt.SetType(header.ICMPv6NeighborAdvert)
|
||||
na := header.NDPNeighborAdvert(pkt.NDPPayload())
|
||||
na.SetSolicitedFlag(true)
|
||||
na.SetOverrideFlag(true)
|
||||
na.SetTargetAddress(host2IPv6Addr.AddressWithPrefix.Address)
|
||||
na.Options().Serialize(header.NDPOptionsSerializer{
|
||||
header.NDPTargetLinkLayerAddressOption(host2NICLinkAddr),
|
||||
})
|
||||
pkt.SetChecksum(header.ICMPv6Checksum(pkt, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, buffer.VectorisedView{}))
|
||||
payloadLength := hdr.UsedLength()
|
||||
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
|
||||
ip.Encode(&header.IPv6Fields{
|
||||
PayloadLength: uint16(payloadLength),
|
||||
NextHeader: uint8(icmp.ProtocolNumber6),
|
||||
HopLimit: header.NDPHopLimit,
|
||||
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
|
||||
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
|
||||
})
|
||||
e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: hdr.View().ToVectorisedView(),
|
||||
}))
|
||||
}
|
||||
|
||||
// Expect the response now that the link address has resolved.
|
||||
test.checkResp(t, e)
|
||||
|
||||
// Since link resolution was already performed, it shouldn't be performed
|
||||
// again.
|
||||
test.rxPkt(e)
|
||||
test.checkResp(t, e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ var _ NDPEndpoint = (*endpoint)(nil)
|
||||
|
||||
type endpoint struct {
|
||||
nic stack.NetworkInterface
|
||||
linkEP stack.LinkEndpoint
|
||||
linkAddrCache stack.LinkAddressCache
|
||||
nud stack.NUDHandler
|
||||
dispatcher stack.TransportDispatcher
|
||||
@@ -364,18 +363,18 @@ 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.linkEP.MTU())
|
||||
return calculateMTU(e.nic.MTU())
|
||||
}
|
||||
|
||||
// MaxHeaderLength returns the maximum length needed by ipv6 headers (and
|
||||
// underlying protocols).
|
||||
func (e *endpoint) MaxHeaderLength() uint16 {
|
||||
return e.linkEP.MaxHeaderLength() + header.IPv6MinimumSize
|
||||
return e.nic.MaxHeaderLength() + header.IPv6MinimumSize
|
||||
}
|
||||
|
||||
// GSOMaxSize returns the maximum GSO packet size.
|
||||
func (e *endpoint) GSOMaxSize() uint32 {
|
||||
if gso, ok := e.linkEP.(stack.GSOEndpoint); ok {
|
||||
if gso, ok := e.nic.(stack.GSOEndpoint); ok {
|
||||
return gso.GSOMaxSize()
|
||||
}
|
||||
return 0
|
||||
@@ -396,7 +395,7 @@ func (e *endpoint) addIPHeader(r *stack.Route, pkt *stack.PacketBuffer, params s
|
||||
}
|
||||
|
||||
func (e *endpoint) packetMustBeFragmented(pkt *stack.PacketBuffer, gso *stack.GSO) bool {
|
||||
return pkt.Size() > int(e.linkEP.MTU()) && (gso == nil || gso.Type == stack.GSONone)
|
||||
return pkt.Size() > int(e.nic.MTU()) && (gso == nil || gso.Type == stack.GSONone)
|
||||
}
|
||||
|
||||
// handleFragments fragments pkt and calls the handler function on each
|
||||
@@ -477,19 +476,19 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, params stack.Netw
|
||||
}
|
||||
|
||||
if e.packetMustBeFragmented(pkt, gso) {
|
||||
sent, remain, err := e.handleFragments(r, gso, e.linkEP.MTU(), pkt, params.Protocol, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
sent, remain, err := e.handleFragments(r, gso, e.nic.MTU(), pkt, params.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
|
||||
// WritePackets(). It'll be faster but cost more memory.
|
||||
return e.linkEP.WritePacket(r, gso, ProtocolNumber, fragPkt)
|
||||
return e.nic.WritePacket(r, gso, ProtocolNumber, fragPkt)
|
||||
})
|
||||
r.Stats().IP.PacketsSent.IncrementBy(uint64(sent))
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(remain))
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.linkEP.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
if err := e.nic.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.Increment()
|
||||
return err
|
||||
}
|
||||
@@ -511,7 +510,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
e.addIPHeader(r, pb, params)
|
||||
if e.packetMustBeFragmented(pb, gso) {
|
||||
current := pb
|
||||
_, _, err := e.handleFragments(r, gso, e.linkEP.MTU(), pb, params.Protocol, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
_, _, err := e.handleFragments(r, gso, e.nic.MTU(), pb, params.Protocol, func(fragPkt *stack.PacketBuffer) *tcpip.Error {
|
||||
// Modify the packet list in place with the new fragments.
|
||||
pkts.InsertAfter(current, fragPkt)
|
||||
current = current.Next()
|
||||
@@ -536,7 +535,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
if len(dropped) == 0 && len(natPkts) == 0 {
|
||||
// Fast path: If no packets are to be dropped then we can just invoke the
|
||||
// faster WritePackets API directly.
|
||||
n, err := e.linkEP.WritePackets(r, gso, pkts, ProtocolNumber)
|
||||
n, err := e.nic.WritePackets(r, gso, pkts, ProtocolNumber)
|
||||
r.Stats().IP.PacketsSent.IncrementBy(uint64(n))
|
||||
if err != nil {
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(pkts.Len() - n))
|
||||
@@ -563,7 +562,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err := e.linkEP.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
if err := e.nic.WritePacket(r, gso, ProtocolNumber, pkt); err != nil {
|
||||
r.Stats().IP.PacketsSent.IncrementBy(uint64(n))
|
||||
r.Stats().IP.OutgoingPacketErrors.IncrementBy(uint64(pkts.Len() - n + len(dropped)))
|
||||
// Dropped packets aren't errors, so include them in
|
||||
@@ -643,7 +642,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// As per RFC 8200 section 4.1, the Hop By Hop extension header is
|
||||
// restricted to appear immediately after an IPv6 fixed header.
|
||||
if previousHeaderStart != 0 {
|
||||
_ = returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownHeader,
|
||||
pointer: previousHeaderStart,
|
||||
}, pkt)
|
||||
@@ -682,7 +681,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// ICMP Parameter Problem, Code 2, message to the packet's
|
||||
// Source Address, pointing to the unrecognized Option Type.
|
||||
//
|
||||
_ = returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownOption,
|
||||
pointer: it.ParseOffset() + optsIt.OptionOffset(),
|
||||
respondToMulticast: true,
|
||||
@@ -707,7 +706,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// header, so we just make sure Segments Left is zero before processing
|
||||
// the next extension header.
|
||||
if extHdr.SegmentsLeft() != 0 {
|
||||
_ = returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
code: header.ICMPv6ErroneousHeader,
|
||||
pointer: it.ParseOffset(),
|
||||
}, pkt)
|
||||
@@ -859,7 +858,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// ICMP Parameter Problem, Code 2, message to the packet's
|
||||
// Source Address, pointing to the unrecognized Option Type.
|
||||
//
|
||||
_ = returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownOption,
|
||||
pointer: it.ParseOffset() + optsIt.OptionOffset(),
|
||||
respondToMulticast: true,
|
||||
@@ -896,7 +895,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// message with Code 4 in response to a packet for which the
|
||||
// transport protocol (e.g., UDP) has no listener, if that transport
|
||||
// protocol has no alternative means to inform the sender.
|
||||
_ = returnError(r, &icmpReasonPortUnreachable{}, pkt)
|
||||
_ = e.protocol.returnError(r, &icmpReasonPortUnreachable{}, pkt)
|
||||
case stack.TransportPacketProtocolUnreachable:
|
||||
// As per RFC 8200 section 4. (page 7):
|
||||
// Extension headers are numbered from IANA IP Protocol Numbers
|
||||
@@ -917,7 +916,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
//
|
||||
// Which when taken together indicate that an unknown protocol should
|
||||
// be treated as an unrecognized next header value.
|
||||
_ = returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownHeader,
|
||||
pointer: it.ParseOffset(),
|
||||
}, pkt)
|
||||
@@ -927,7 +926,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
}
|
||||
|
||||
default:
|
||||
_ = returnError(r, &icmpReasonParameterProblem{
|
||||
_ = e.protocol.returnError(r, &icmpReasonParameterProblem{
|
||||
code: header.ICMPv6UnknownHeader,
|
||||
pointer: it.ParseOffset(),
|
||||
}, pkt)
|
||||
@@ -1302,7 +1301,6 @@ func (*protocol) ParseAddresses(v buffer.View) (src, dst tcpip.Address) {
|
||||
func (p *protocol) NewEndpoint(nic stack.NetworkInterface, linkAddrCache stack.LinkAddressCache, nud stack.NUDHandler, dispatcher stack.TransportDispatcher) stack.NetworkEndpoint {
|
||||
e := &endpoint{
|
||||
nic: nic,
|
||||
linkEP: nic.LinkEndpoint(),
|
||||
linkAddrCache: linkAddrCache,
|
||||
nud: nud,
|
||||
dispatcher: dispatcher,
|
||||
|
||||
@@ -1289,7 +1289,7 @@ func (ndp *ndpState) generateSLAACAddr(prefix tcpip.Subnet, state *slaacPrefixSt
|
||||
//
|
||||
// TODO(b/141011931): Validate a LinkEndpoint's link address (provided by
|
||||
// LinkEndpoint.LinkAddress) before reaching this point.
|
||||
linkAddr := ndp.ep.linkEP.LinkAddress()
|
||||
linkAddr := ndp.ep.nic.LinkAddress()
|
||||
if !header.IsValidUnicastEthernetAddress(linkAddr) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ go_library(
|
||||
srcs = [
|
||||
"addressable_endpoint_state.go",
|
||||
"conntrack.go",
|
||||
"forwarder.go",
|
||||
"headertype_string.go",
|
||||
"icmp_rate_limit.go",
|
||||
"iptables.go",
|
||||
@@ -73,6 +72,7 @@ go_library(
|
||||
"nud.go",
|
||||
"packet_buffer.go",
|
||||
"packet_buffer_list.go",
|
||||
"pending_packets.go",
|
||||
"rand.go",
|
||||
"registration.go",
|
||||
"route.go",
|
||||
@@ -123,7 +123,6 @@ go_test(
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/link/channel",
|
||||
"//pkg/tcpip/link/loopback",
|
||||
"//pkg/tcpip/network/arp",
|
||||
"//pkg/tcpip/network/ipv4",
|
||||
"//pkg/tcpip/network/ipv6",
|
||||
"//pkg/tcpip/ports",
|
||||
@@ -139,7 +138,7 @@ go_test(
|
||||
name = "stack_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"forwarder_test.go",
|
||||
"forwarding_test.go",
|
||||
"linkaddrcache_test.go",
|
||||
"neighbor_cache_test.go",
|
||||
"neighbor_entry_test.go",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user