summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/stack
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/stack')
-rw-r--r--pkg/tcpip/stack/BUILD1
-rw-r--r--pkg/tcpip/stack/addressable_endpoint_state.go34
-rw-r--r--pkg/tcpip/stack/conntrack.go12
-rw-r--r--pkg/tcpip/stack/forwarding_test.go219
-rw-r--r--pkg/tcpip/stack/iptables.go6
-rw-r--r--pkg/tcpip/stack/linkaddrcache.go199
-rw-r--r--pkg/tcpip/stack/linkaddrcache_test.go132
-rw-r--r--pkg/tcpip/stack/ndp_test.go31
-rw-r--r--pkg/tcpip/stack/neighbor_cache.go85
-rw-r--r--pkg/tcpip/stack/neighbor_cache_test.go593
-rw-r--r--pkg/tcpip/stack/neighbor_entry.go61
-rw-r--r--pkg/tcpip/stack/neighbor_entry_test.go370
-rw-r--r--pkg/tcpip/stack/nic.go325
-rw-r--r--pkg/tcpip/stack/nic_test.go38
-rw-r--r--pkg/tcpip/stack/nud.go19
-rw-r--r--pkg/tcpip/stack/nud_test.go226
-rw-r--r--pkg/tcpip/stack/packet_buffer.go6
-rw-r--r--pkg/tcpip/stack/packet_buffer_unsafe.go19
-rw-r--r--pkg/tcpip/stack/pending_packets.go24
-rw-r--r--pkg/tcpip/stack/registration.go156
-rw-r--r--pkg/tcpip/stack/route.go51
-rw-r--r--pkg/tcpip/stack/stack.go377
-rw-r--r--pkg/tcpip/stack/stack_options.go41
-rw-r--r--pkg/tcpip/stack/stack_test.go277
-rw-r--r--pkg/tcpip/stack/transport_demuxer.go45
-rw-r--r--pkg/tcpip/stack/transport_demuxer_test.go6
-rw-r--r--pkg/tcpip/stack/transport_test.go66
27 files changed, 1822 insertions, 1597 deletions
diff --git a/pkg/tcpip/stack/BUILD b/pkg/tcpip/stack/BUILD
index bb30556cf..ee23c9b98 100644
--- a/pkg/tcpip/stack/BUILD
+++ b/pkg/tcpip/stack/BUILD
@@ -72,6 +72,7 @@ go_library(
"nud.go",
"packet_buffer.go",
"packet_buffer_list.go",
+ "packet_buffer_unsafe.go",
"pending_packets.go",
"rand.go",
"registration.go",
diff --git a/pkg/tcpip/stack/addressable_endpoint_state.go b/pkg/tcpip/stack/addressable_endpoint_state.go
index cd423bf71..e5590ecc0 100644
--- a/pkg/tcpip/stack/addressable_endpoint_state.go
+++ b/pkg/tcpip/stack/addressable_endpoint_state.go
@@ -117,7 +117,7 @@ func (a *AddressableEndpointState) releaseAddressStateLocked(addrState *addressS
}
// AddAndAcquirePermanentAddress implements AddressableEndpoint.
-func (a *AddressableEndpointState) AddAndAcquirePermanentAddress(addr tcpip.AddressWithPrefix, peb PrimaryEndpointBehavior, configType AddressConfigType, deprecated bool) (AddressEndpoint, *tcpip.Error) {
+func (a *AddressableEndpointState) AddAndAcquirePermanentAddress(addr tcpip.AddressWithPrefix, peb PrimaryEndpointBehavior, configType AddressConfigType, deprecated bool) (AddressEndpoint, tcpip.Error) {
a.mu.Lock()
defer a.mu.Unlock()
ep, err := a.addAndAcquireAddressLocked(addr, peb, configType, deprecated, true /* permanent */)
@@ -143,10 +143,10 @@ func (a *AddressableEndpointState) AddAndAcquirePermanentAddress(addr tcpip.Addr
// AddAndAcquireTemporaryAddress adds a temporary address.
//
-// Returns tcpip.ErrDuplicateAddress if the address exists.
+// Returns *tcpip.ErrDuplicateAddress if the address exists.
//
// The temporary address's endpoint is acquired and returned.
-func (a *AddressableEndpointState) AddAndAcquireTemporaryAddress(addr tcpip.AddressWithPrefix, peb PrimaryEndpointBehavior) (AddressEndpoint, *tcpip.Error) {
+func (a *AddressableEndpointState) AddAndAcquireTemporaryAddress(addr tcpip.AddressWithPrefix, peb PrimaryEndpointBehavior) (AddressEndpoint, tcpip.Error) {
a.mu.Lock()
defer a.mu.Unlock()
ep, err := a.addAndAcquireAddressLocked(addr, peb, AddressConfigStatic, false /* deprecated */, false /* permanent */)
@@ -176,11 +176,11 @@ func (a *AddressableEndpointState) AddAndAcquireTemporaryAddress(addr tcpip.Addr
// If the addressable endpoint already has the address in a non-permanent state,
// and addAndAcquireAddressLocked is adding a permanent address, that address is
// promoted in place and its properties set to the properties provided. If the
-// address already exists in any other state, then tcpip.ErrDuplicateAddress is
+// address already exists in any other state, then *tcpip.ErrDuplicateAddress is
// returned, regardless the kind of address that is being added.
//
// Precondition: a.mu must be write locked.
-func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.AddressWithPrefix, peb PrimaryEndpointBehavior, configType AddressConfigType, deprecated, permanent bool) (*addressState, *tcpip.Error) {
+func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.AddressWithPrefix, peb PrimaryEndpointBehavior, configType AddressConfigType, deprecated, permanent bool) (*addressState, tcpip.Error) {
// attemptAddToPrimary is false when the address is already in the primary
// address list.
attemptAddToPrimary := true
@@ -190,7 +190,7 @@ func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.Address
// We are adding a non-permanent address but the address exists. No need
// to go any further since we can only promote existing temporary/expired
// addresses to permanent.
- return nil, tcpip.ErrDuplicateAddress
+ return nil, &tcpip.ErrDuplicateAddress{}
}
addrState.mu.Lock()
@@ -198,7 +198,7 @@ func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.Address
addrState.mu.Unlock()
// We are adding a permanent address but a permanent address already
// exists.
- return nil, tcpip.ErrDuplicateAddress
+ return nil, &tcpip.ErrDuplicateAddress{}
}
if addrState.mu.refs == 0 {
@@ -293,7 +293,7 @@ func (a *AddressableEndpointState) addAndAcquireAddressLocked(addr tcpip.Address
}
// RemovePermanentAddress implements AddressableEndpoint.
-func (a *AddressableEndpointState) RemovePermanentAddress(addr tcpip.Address) *tcpip.Error {
+func (a *AddressableEndpointState) RemovePermanentAddress(addr tcpip.Address) tcpip.Error {
a.mu.Lock()
defer a.mu.Unlock()
return a.removePermanentAddressLocked(addr)
@@ -303,10 +303,10 @@ func (a *AddressableEndpointState) RemovePermanentAddress(addr tcpip.Address) *t
// requirements.
//
// Precondition: a.mu must be write locked.
-func (a *AddressableEndpointState) removePermanentAddressLocked(addr tcpip.Address) *tcpip.Error {
+func (a *AddressableEndpointState) removePermanentAddressLocked(addr tcpip.Address) tcpip.Error {
addrState, ok := a.mu.endpoints[addr]
if !ok {
- return tcpip.ErrBadLocalAddress
+ return &tcpip.ErrBadLocalAddress{}
}
return a.removePermanentEndpointLocked(addrState)
@@ -314,10 +314,10 @@ func (a *AddressableEndpointState) removePermanentAddressLocked(addr tcpip.Addre
// RemovePermanentEndpoint removes the passed endpoint if it is associated with
// a and permanent.
-func (a *AddressableEndpointState) RemovePermanentEndpoint(ep AddressEndpoint) *tcpip.Error {
+func (a *AddressableEndpointState) RemovePermanentEndpoint(ep AddressEndpoint) tcpip.Error {
addrState, ok := ep.(*addressState)
if !ok || addrState.addressableEndpointState != a {
- return tcpip.ErrInvalidEndpointState
+ return &tcpip.ErrInvalidEndpointState{}
}
a.mu.Lock()
@@ -329,9 +329,9 @@ func (a *AddressableEndpointState) RemovePermanentEndpoint(ep AddressEndpoint) *
// requirements.
//
// Precondition: a.mu must be write locked.
-func (a *AddressableEndpointState) removePermanentEndpointLocked(addrState *addressState) *tcpip.Error {
+func (a *AddressableEndpointState) removePermanentEndpointLocked(addrState *addressState) tcpip.Error {
if !addrState.GetKind().IsPermanent() {
- return tcpip.ErrBadLocalAddress
+ return &tcpip.ErrBadLocalAddress{}
}
addrState.SetKind(PermanentExpired)
@@ -574,9 +574,11 @@ func (a *AddressableEndpointState) Cleanup() {
defer a.mu.Unlock()
for _, ep := range a.mu.endpoints {
- // removePermanentEndpointLocked returns tcpip.ErrBadLocalAddress if ep is
+ // removePermanentEndpointLocked returns *tcpip.ErrBadLocalAddress if ep is
// not a permanent address.
- if err := a.removePermanentEndpointLocked(ep); err != nil && err != tcpip.ErrBadLocalAddress {
+ switch err := a.removePermanentEndpointLocked(ep); err.(type) {
+ case nil, *tcpip.ErrBadLocalAddress:
+ default:
panic(fmt.Sprintf("unexpected error from removePermanentEndpointLocked(%s): %s", ep.addr, err))
}
}
diff --git a/pkg/tcpip/stack/conntrack.go b/pkg/tcpip/stack/conntrack.go
index 5e649cca6..54617f2e6 100644
--- a/pkg/tcpip/stack/conntrack.go
+++ b/pkg/tcpip/stack/conntrack.go
@@ -198,15 +198,15 @@ type bucket struct {
// TCP header.
//
// Preconditions: pkt.NetworkHeader() is valid.
-func packetToTupleID(pkt *PacketBuffer) (tupleID, *tcpip.Error) {
+func packetToTupleID(pkt *PacketBuffer) (tupleID, tcpip.Error) {
netHeader := pkt.Network()
if netHeader.TransportProtocol() != header.TCPProtocolNumber {
- return tupleID{}, tcpip.ErrUnknownProtocol
+ return tupleID{}, &tcpip.ErrUnknownProtocol{}
}
tcpHeader := header.TCP(pkt.TransportHeader().View())
if len(tcpHeader) < header.TCPMinimumSize {
- return tupleID{}, tcpip.ErrUnknownProtocol
+ return tupleID{}, &tcpip.ErrUnknownProtocol{}
}
return tupleID{
@@ -617,7 +617,7 @@ func (ct *ConnTrack) reapTupleLocked(tuple *tuple, bucket int, now time.Time) bo
return true
}
-func (ct *ConnTrack) originalDst(epID TransportEndpointID, netProto tcpip.NetworkProtocolNumber) (tcpip.Address, uint16, *tcpip.Error) {
+func (ct *ConnTrack) originalDst(epID TransportEndpointID, netProto tcpip.NetworkProtocolNumber) (tcpip.Address, uint16, tcpip.Error) {
// Lookup the connection. The reply's original destination
// describes the original address.
tid := tupleID{
@@ -631,10 +631,10 @@ func (ct *ConnTrack) originalDst(epID TransportEndpointID, netProto tcpip.Networ
conn, _ := ct.connForTID(tid)
if conn == nil {
// Not a tracked connection.
- return "", 0, tcpip.ErrNotConnected
+ return "", 0, &tcpip.ErrNotConnected{}
} else if conn.manip == manipNone {
// Unmanipulated connection.
- return "", 0, tcpip.ErrInvalidOptionValue
+ return "", 0, &tcpip.ErrInvalidOptionValue{}
}
return conn.original.dstAddr, conn.original.dstPort, nil
diff --git a/pkg/tcpip/stack/forwarding_test.go b/pkg/tcpip/stack/forwarding_test.go
index d29c9a49b..c24f56ece 100644
--- a/pkg/tcpip/stack/forwarding_test.go
+++ b/pkg/tcpip/stack/forwarding_test.go
@@ -41,6 +41,7 @@ const (
protocolNumberOffset = 2
)
+var _ LinkAddressResolver = (*fwdTestNetworkEndpoint)(nil)
var _ NetworkEndpoint = (*fwdTestNetworkEndpoint)(nil)
// fwdTestNetworkEndpoint is a network-layer protocol endpoint.
@@ -55,7 +56,7 @@ type fwdTestNetworkEndpoint struct {
dispatcher TransportDispatcher
}
-func (*fwdTestNetworkEndpoint) Enable() *tcpip.Error {
+func (*fwdTestNetworkEndpoint) Enable() tcpip.Error {
return nil
}
@@ -112,7 +113,7 @@ func (f *fwdTestNetworkEndpoint) NetworkProtocolNumber() tcpip.NetworkProtocolNu
return f.proto.Number()
}
-func (f *fwdTestNetworkEndpoint) WritePacket(r *Route, gso *GSO, params NetworkHeaderParams, pkt *PacketBuffer) *tcpip.Error {
+func (f *fwdTestNetworkEndpoint) WritePacket(r *Route, gso *GSO, params NetworkHeaderParams, pkt *PacketBuffer) tcpip.Error {
// Add the protocol's header to the packet and send it to the link
// endpoint.
b := pkt.NetworkHeader().Push(fwdTestNetHeaderLen)
@@ -124,14 +125,14 @@ func (f *fwdTestNetworkEndpoint) WritePacket(r *Route, gso *GSO, params NetworkH
}
// WritePackets implements LinkEndpoint.WritePackets.
-func (*fwdTestNetworkEndpoint) WritePackets(r *Route, gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, *tcpip.Error) {
+func (*fwdTestNetworkEndpoint) WritePackets(r *Route, gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, tcpip.Error) {
panic("not implemented")
}
-func (f *fwdTestNetworkEndpoint) WriteHeaderIncludedPacket(r *Route, pkt *PacketBuffer) *tcpip.Error {
+func (f *fwdTestNetworkEndpoint) WriteHeaderIncludedPacket(r *Route, pkt *PacketBuffer) tcpip.Error {
// The network header should not already be populated.
if _, ok := pkt.NetworkHeader().Consume(fwdTestNetHeaderLen); !ok {
- return tcpip.ErrMalformedHeader
+ return &tcpip.ErrMalformedHeader{}
}
return f.nic.WritePacket(r, nil /* gso */, fwdTestNetNumber, pkt)
@@ -153,7 +154,6 @@ type fwdTestNetworkEndpointStats struct{}
// IsNetworkEndpointStats implements stack.NetworkEndpointStats.
func (*fwdTestNetworkEndpointStats) IsNetworkEndpointStats() {}
-var _ LinkAddressResolver = (*fwdTestNetworkProtocol)(nil)
var _ NetworkProtocol = (*fwdTestNetworkProtocol)(nil)
// fwdTestNetworkProtocol is a network-layer protocol that implements Address
@@ -161,10 +161,9 @@ var _ NetworkProtocol = (*fwdTestNetworkProtocol)(nil)
type fwdTestNetworkProtocol struct {
stack *Stack
- addrCache *linkAddrCache
- neigh *neighborCache
+ neighborTable neighborTable
addrResolveDelay time.Duration
- onLinkAddressResolved func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, _ tcpip.LinkAddress)
+ onLinkAddressResolved func(neighborTable, tcpip.Address, tcpip.LinkAddress)
onResolveStaticAddress func(tcpip.Address) (tcpip.LinkAddress, bool)
mu struct {
@@ -197,7 +196,7 @@ func (*fwdTestNetworkProtocol) Parse(pkt *PacketBuffer) (tcpip.TransportProtocol
return tcpip.TransportProtocolNumber(netHeader[protocolNumberOffset]), true, true
}
-func (f *fwdTestNetworkProtocol) NewEndpoint(nic NetworkInterface, _ LinkAddressCache, _ NUDHandler, dispatcher TransportDispatcher) NetworkEndpoint {
+func (f *fwdTestNetworkProtocol) NewEndpoint(nic NetworkInterface, dispatcher TransportDispatcher) NetworkEndpoint {
e := &fwdTestNetworkEndpoint{
nic: nic,
proto: f,
@@ -207,35 +206,35 @@ func (f *fwdTestNetworkProtocol) NewEndpoint(nic NetworkInterface, _ LinkAddress
return e
}
-func (*fwdTestNetworkProtocol) SetOption(tcpip.SettableNetworkProtocolOption) *tcpip.Error {
- return tcpip.ErrUnknownProtocolOption
+func (*fwdTestNetworkProtocol) SetOption(tcpip.SettableNetworkProtocolOption) tcpip.Error {
+ return &tcpip.ErrUnknownProtocolOption{}
}
-func (*fwdTestNetworkProtocol) Option(tcpip.GettableNetworkProtocolOption) *tcpip.Error {
- return tcpip.ErrUnknownProtocolOption
+func (*fwdTestNetworkProtocol) Option(tcpip.GettableNetworkProtocolOption) tcpip.Error {
+ return &tcpip.ErrUnknownProtocolOption{}
}
func (*fwdTestNetworkProtocol) Close() {}
func (*fwdTestNetworkProtocol) Wait() {}
-func (f *fwdTestNetworkProtocol) LinkAddressRequest(addr, _ tcpip.Address, remoteLinkAddr tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
- if f.onLinkAddressResolved != nil {
- time.AfterFunc(f.addrResolveDelay, func() {
- f.onLinkAddressResolved(f.addrCache, f.neigh, addr, remoteLinkAddr)
+func (f *fwdTestNetworkEndpoint) LinkAddressRequest(addr, _ tcpip.Address, remoteLinkAddr tcpip.LinkAddress) tcpip.Error {
+ if fn := f.proto.onLinkAddressResolved; fn != nil {
+ time.AfterFunc(f.proto.addrResolveDelay, func() {
+ fn(f.proto.neighborTable, addr, remoteLinkAddr)
})
}
return nil
}
-func (f *fwdTestNetworkProtocol) ResolveStaticAddress(addr tcpip.Address) (tcpip.LinkAddress, bool) {
- if f.onResolveStaticAddress != nil {
- return f.onResolveStaticAddress(addr)
+func (f *fwdTestNetworkEndpoint) ResolveStaticAddress(addr tcpip.Address) (tcpip.LinkAddress, bool) {
+ if fn := f.proto.onResolveStaticAddress; fn != nil {
+ return fn(addr)
}
return "", false
}
-func (*fwdTestNetworkProtocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
+func (*fwdTestNetworkEndpoint) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
return fwdTestNetNumber
}
@@ -319,7 +318,7 @@ func (e *fwdTestLinkEndpoint) LinkAddress() tcpip.LinkAddress {
return e.linkAddr
}
-func (e fwdTestLinkEndpoint) WritePacket(r RouteInfo, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) *tcpip.Error {
+func (e fwdTestLinkEndpoint) WritePacket(r RouteInfo, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) tcpip.Error {
p := fwdTestPacketInfo{
RemoteLinkAddress: r.RemoteLinkAddress,
LocalLinkAddress: r.LocalLinkAddress,
@@ -335,7 +334,7 @@ func (e fwdTestLinkEndpoint) WritePacket(r RouteInfo, gso *GSO, protocol tcpip.N
}
// WritePackets stores outbound packets into the channel.
-func (e *fwdTestLinkEndpoint) WritePackets(r RouteInfo, gso *GSO, pkts PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
+func (e *fwdTestLinkEndpoint) WritePackets(r RouteInfo, gso *GSO, pkts PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
n := 0
for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
e.WritePacket(r, gso, protocol, pkt)
@@ -401,11 +400,9 @@ func fwdTestNetFactory(t *testing.T, proto *fwdTestNetworkProtocol, useNeighborC
if !ok {
t.Fatal("NIC 2 does not exist")
}
- if useNeighborCache {
- // Control the neighbor cache for NIC 2.
- proto.neigh = nic.neigh
- } else {
- proto.addrCache = nic.linkAddrCache
+
+ if l, ok := nic.linkAddrResolvers[fwdTestNetNumber]; ok {
+ proto.neighborTable = l.neighborTable
}
// Route all packets to NIC 2.
@@ -482,43 +479,35 @@ func TestForwardingWithFakeResolver(t *testing.T) {
tests := []struct {
name string
useNeighborCache bool
- proto *fwdTestNetworkProtocol
}{
{
name: "linkAddrCache",
useNeighborCache: false,
- proto: &fwdTestNetworkProtocol{
- addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, _ tcpip.LinkAddress) {
- // Any address will be resolved to the link address "c".
- cache.AddLinkAddress(addr, "c")
- },
- },
},
{
name: "neighborCache",
useNeighborCache: true,
- proto: &fwdTestNetworkProtocol{
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ proto := fwdTestNetworkProtocol{
addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) {
+ onLinkAddressResolved: func(neigh neighborTable, addr tcpip.Address, linkAddr tcpip.LinkAddress) {
t.Helper()
- if len(remoteLinkAddr) != 0 {
- t.Fatalf("got remoteLinkAddr=%q, want unspecified", remoteLinkAddr)
+ if len(linkAddr) != 0 {
+ t.Fatalf("got linkAddr=%q, want unspecified", linkAddr)
}
// Any address will be resolved to the link address "c".
- neigh.HandleConfirmation(addr, "c", ReachabilityConfirmationFlags{
+ neigh.handleConfirmation(addr, "c", ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
IsRouter: false,
})
},
- },
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- ep1, ep2 := fwdTestNetFactory(t, test.proto, test.useNeighborCache)
+ }
+ ep1, ep2 := fwdTestNetFactory(t, &proto, test.useNeighborCache)
// Inject an inbound packet to address 3 on NIC 1, and see if it is
// forwarded to NIC 2.
@@ -573,7 +562,7 @@ func TestForwardingWithNoResolver(t *testing.T) {
func TestForwardingResolutionFailsForQueuedPackets(t *testing.T) {
proto := &fwdTestNetworkProtocol{
addrResolveDelay: 50 * time.Millisecond,
- onLinkAddressResolved: func(*linkAddrCache, *neighborCache, tcpip.Address, tcpip.LinkAddress) {
+ onLinkAddressResolved: func(neighborTable, tcpip.Address, tcpip.LinkAddress) {
// Don't resolve the link address.
},
}
@@ -606,49 +595,38 @@ func TestForwardingWithFakeResolverPartialTimeout(t *testing.T) {
tests := []struct {
name string
useNeighborCache bool
- proto *fwdTestNetworkProtocol
}{
{
name: "linkAddrCache",
useNeighborCache: false,
- proto: &fwdTestNetworkProtocol{
- addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, _ tcpip.LinkAddress) {
- // Only packets to address 3 will be resolved to the
- // link address "c".
- if addr == "\x03" {
- cache.AddLinkAddress(addr, "c")
- }
- },
- },
},
{
name: "neighborCache",
useNeighborCache: true,
- proto: &fwdTestNetworkProtocol{
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ proto := fwdTestNetworkProtocol{
addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) {
+ onLinkAddressResolved: func(neigh neighborTable, addr tcpip.Address, linkAddr tcpip.LinkAddress) {
t.Helper()
- if len(remoteLinkAddr) != 0 {
- t.Fatalf("got remoteLinkAddr=%q, want unspecified", remoteLinkAddr)
+ if len(linkAddr) != 0 {
+ t.Fatalf("got linkAddr=%q, want unspecified", linkAddr)
}
// Only packets to address 3 will be resolved to the
// link address "c".
if addr == "\x03" {
- neigh.HandleConfirmation(addr, "c", ReachabilityConfirmationFlags{
+ neigh.handleConfirmation(addr, "c", ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
IsRouter: false,
})
}
},
- },
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- ep1, ep2 := fwdTestNetFactory(t, test.proto, test.useNeighborCache)
+ }
+ ep1, ep2 := fwdTestNetFactory(t, &proto, test.useNeighborCache)
// Inject an inbound packet to address 4 on NIC 1. This packet should
// not be forwarded.
@@ -693,43 +671,35 @@ func TestForwardingWithFakeResolverTwoPackets(t *testing.T) {
tests := []struct {
name string
useNeighborCache bool
- proto *fwdTestNetworkProtocol
}{
{
name: "linkAddrCache",
useNeighborCache: false,
- proto: &fwdTestNetworkProtocol{
- addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, _ tcpip.LinkAddress) {
- // Any packets will be resolved to the link address "c".
- cache.AddLinkAddress(addr, "c")
- },
- },
},
{
name: "neighborCache",
useNeighborCache: true,
- proto: &fwdTestNetworkProtocol{
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ proto := fwdTestNetworkProtocol{
addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) {
+ onLinkAddressResolved: func(neigh neighborTable, addr tcpip.Address, linkAddr tcpip.LinkAddress) {
t.Helper()
- if len(remoteLinkAddr) != 0 {
- t.Fatalf("got remoteLinkAddr=%q, want unspecified", remoteLinkAddr)
+ if len(linkAddr) != 0 {
+ t.Fatalf("got linkAddr=%q, want unspecified", linkAddr)
}
// Any packets will be resolved to the link address "c".
- neigh.HandleConfirmation(addr, "c", ReachabilityConfirmationFlags{
+ neigh.handleConfirmation(addr, "c", ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
IsRouter: false,
})
},
- },
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- ep1, ep2 := fwdTestNetFactory(t, test.proto, test.useNeighborCache)
+ }
+ ep1, ep2 := fwdTestNetFactory(t, &proto, test.useNeighborCache)
// Inject two inbound packets to address 3 on NIC 1.
for i := 0; i < 2; i++ {
@@ -769,43 +739,35 @@ func TestForwardingWithFakeResolverManyPackets(t *testing.T) {
tests := []struct {
name string
useNeighborCache bool
- proto *fwdTestNetworkProtocol
}{
{
name: "linkAddrCache",
useNeighborCache: false,
- proto: &fwdTestNetworkProtocol{
- addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, _ tcpip.LinkAddress) {
- // Any packets will be resolved to the link address "c".
- cache.AddLinkAddress(addr, "c")
- },
- },
},
{
name: "neighborCache",
useNeighborCache: true,
- proto: &fwdTestNetworkProtocol{
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ proto := fwdTestNetworkProtocol{
addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) {
+ onLinkAddressResolved: func(neigh neighborTable, addr tcpip.Address, linkAddr tcpip.LinkAddress) {
t.Helper()
- if len(remoteLinkAddr) != 0 {
- t.Fatalf("got remoteLinkAddr=%q, want unspecified", remoteLinkAddr)
+ if len(linkAddr) != 0 {
+ t.Fatalf("got linkAddr=%q, want unspecified", linkAddr)
}
// Any packets will be resolved to the link address "c".
- neigh.HandleConfirmation(addr, "c", ReachabilityConfirmationFlags{
+ neigh.handleConfirmation(addr, "c", ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
IsRouter: false,
})
},
- },
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- ep1, ep2 := fwdTestNetFactory(t, test.proto, test.useNeighborCache)
+ }
+ ep1, ep2 := fwdTestNetFactory(t, &proto, test.useNeighborCache)
for i := 0; i < maxPendingPacketsPerResolution+5; i++ {
// Inject inbound 'maxPendingPacketsPerResolution + 5' packets on NIC 1.
@@ -864,38 +826,31 @@ func TestForwardingWithFakeResolverManyResolutions(t *testing.T) {
{
name: "linkAddrCache",
useNeighborCache: false,
- proto: &fwdTestNetworkProtocol{
- addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, _ tcpip.LinkAddress) {
- // Any packets will be resolved to the link address "c".
- cache.AddLinkAddress(addr, "c")
- },
- },
},
{
name: "neighborCache",
useNeighborCache: true,
- proto: &fwdTestNetworkProtocol{
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ proto := fwdTestNetworkProtocol{
addrResolveDelay: 500 * time.Millisecond,
- onLinkAddressResolved: func(cache *linkAddrCache, neigh *neighborCache, addr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) {
+ onLinkAddressResolved: func(neigh neighborTable, addr tcpip.Address, linkAddr tcpip.LinkAddress) {
t.Helper()
- if len(remoteLinkAddr) != 0 {
- t.Fatalf("got remoteLinkAddr=%q, want unspecified", remoteLinkAddr)
+ if len(linkAddr) != 0 {
+ t.Fatalf("got linkAddr=%q, want unspecified", linkAddr)
}
// Any packets will be resolved to the link address "c".
- neigh.HandleConfirmation(addr, "c", ReachabilityConfirmationFlags{
+ neigh.handleConfirmation(addr, "c", ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
IsRouter: false,
})
},
- },
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- ep1, ep2 := fwdTestNetFactory(t, test.proto, test.useNeighborCache)
+ }
+ ep1, ep2 := fwdTestNetFactory(t, &proto, test.useNeighborCache)
for i := 0; i < maxPendingResolutions+5; i++ {
// Inject inbound 'maxPendingResolutions + 5' packets on NIC 1.
diff --git a/pkg/tcpip/stack/iptables.go b/pkg/tcpip/stack/iptables.go
index 04af933a6..63832c200 100644
--- a/pkg/tcpip/stack/iptables.go
+++ b/pkg/tcpip/stack/iptables.go
@@ -229,7 +229,7 @@ func (it *IPTables) GetTable(id TableID, ipv6 bool) Table {
// ReplaceTable replaces or inserts table by name. It panics when an invalid id
// is provided.
-func (it *IPTables) ReplaceTable(id TableID, table Table, ipv6 bool) *tcpip.Error {
+func (it *IPTables) ReplaceTable(id TableID, table Table, ipv6 bool) tcpip.Error {
it.mu.Lock()
defer it.mu.Unlock()
// If iptables is being enabled, initialize the conntrack table and
@@ -483,11 +483,11 @@ func (it *IPTables) checkRule(hook Hook, pkt *PacketBuffer, table Table, ruleIdx
// OriginalDst returns the original destination of redirected connections. It
// returns an error if the connection doesn't exist or isn't redirected.
-func (it *IPTables) OriginalDst(epID TransportEndpointID, netProto tcpip.NetworkProtocolNumber) (tcpip.Address, uint16, *tcpip.Error) {
+func (it *IPTables) OriginalDst(epID TransportEndpointID, netProto tcpip.NetworkProtocolNumber) (tcpip.Address, uint16, tcpip.Error) {
it.mu.RLock()
defer it.mu.RUnlock()
if !it.modified {
- return "", 0, tcpip.ErrNotConnected
+ return "", 0, &tcpip.ErrNotConnected{}
}
return it.connections.originalDst(epID, netProto)
}
diff --git a/pkg/tcpip/stack/linkaddrcache.go b/pkg/tcpip/stack/linkaddrcache.go
index ba6d56a7d..5b6b58b1d 100644
--- a/pkg/tcpip/stack/linkaddrcache.go
+++ b/pkg/tcpip/stack/linkaddrcache.go
@@ -24,8 +24,6 @@ import (
const linkAddrCacheSize = 512 // max cache entries
-var _ LinkAddressCache = (*linkAddrCache)(nil)
-
// linkAddrCache is a fixed-sized cache mapping IP addresses to link addresses.
//
// The entries are stored in a ring buffer, oldest entry replaced first.
@@ -34,6 +32,8 @@ var _ LinkAddressCache = (*linkAddrCache)(nil)
type linkAddrCache struct {
nic *NIC
+ linkRes LinkAddressResolver
+
// ageLimit is how long a cache entry is valid for.
ageLimit time.Duration
@@ -45,7 +45,7 @@ type linkAddrCache struct {
// resolved before failing.
resolutionAttempts int
- cache struct {
+ mu struct {
sync.Mutex
table map[tcpip.Address]*linkAddrEntry
lru linkAddrEntryList
@@ -83,32 +83,32 @@ type linkAddrEntry struct {
cache *linkAddrCache
- // TODO(gvisor.dev/issue/5150): move these fields under mu.
- // mu protects the fields below.
- mu sync.RWMutex
+ mu struct {
+ sync.RWMutex
- addr tcpip.Address
- linkAddr tcpip.LinkAddress
- expiration time.Time
- s entryState
+ addr tcpip.Address
+ linkAddr tcpip.LinkAddress
+ expiration time.Time
+ s entryState
- // done is closed when address resolution is complete. It is nil iff s is
- // incomplete and resolution is not yet in progress.
- done chan struct{}
+ // done is closed when address resolution is complete. It is nil iff s is
+ // incomplete and resolution is not yet in progress.
+ done chan struct{}
- // onResolve is called with the result of address resolution.
- onResolve []func(LinkResolutionResult)
+ // onResolve is called with the result of address resolution.
+ onResolve []func(LinkResolutionResult)
+ }
}
func (e *linkAddrEntry) notifyCompletionLocked(linkAddr tcpip.LinkAddress) {
res := LinkResolutionResult{LinkAddress: linkAddr, Success: len(linkAddr) != 0}
- for _, callback := range e.onResolve {
+ for _, callback := range e.mu.onResolve {
callback(res)
}
- e.onResolve = nil
- if ch := e.done; ch != nil {
+ e.mu.onResolve = nil
+ if ch := e.mu.done; ch != nil {
close(ch)
- e.done = nil
+ e.mu.done = nil
// Dequeue the pending packets in a new goroutine to not hold up the current
// goroutine as writing packets may be a costly operation.
//
@@ -129,30 +129,30 @@ func (e *linkAddrEntry) notifyCompletionLocked(linkAddr tcpip.LinkAddress) {
//
// Precondition: e.mu must be locked
func (e *linkAddrEntry) changeStateLocked(ns entryState, expiration time.Time) {
- if e.s == incomplete && ns == ready {
- e.notifyCompletionLocked(e.linkAddr)
+ if e.mu.s == incomplete && ns == ready {
+ e.notifyCompletionLocked(e.mu.linkAddr)
}
- if expiration.IsZero() || expiration.After(e.expiration) {
- e.expiration = expiration
+ if expiration.IsZero() || expiration.After(e.mu.expiration) {
+ e.mu.expiration = expiration
}
- e.s = ns
+ e.mu.s = ns
}
// add adds a k -> v mapping to the cache.
-func (c *linkAddrCache) AddLinkAddress(k tcpip.Address, v tcpip.LinkAddress) {
+func (c *linkAddrCache) add(k tcpip.Address, v tcpip.LinkAddress) {
// Calculate expiration time before acquiring the lock, since expiration is
// relative to the time when information was learned, rather than when it
// happened to be inserted into the cache.
expiration := time.Now().Add(c.ageLimit)
- c.cache.Lock()
+ c.mu.Lock()
entry := c.getOrCreateEntryLocked(k)
- c.cache.Unlock()
-
entry.mu.Lock()
defer entry.mu.Unlock()
- entry.linkAddr = v
+ c.mu.Unlock()
+
+ entry.mu.linkAddr = v
entry.changeStateLocked(ready, expiration)
}
@@ -166,18 +166,18 @@ func (c *linkAddrCache) AddLinkAddress(k tcpip.Address, v tcpip.LinkAddress) {
// cache is not full, a new entry with state incomplete is allocated and
// returned.
func (c *linkAddrCache) getOrCreateEntryLocked(k tcpip.Address) *linkAddrEntry {
- if entry, ok := c.cache.table[k]; ok {
- c.cache.lru.Remove(entry)
- c.cache.lru.PushFront(entry)
+ if entry, ok := c.mu.table[k]; ok {
+ c.mu.lru.Remove(entry)
+ c.mu.lru.PushFront(entry)
return entry
}
var entry *linkAddrEntry
- if len(c.cache.table) == linkAddrCacheSize {
- entry = c.cache.lru.Back()
+ if len(c.mu.table) == linkAddrCacheSize {
+ entry = c.mu.lru.Back()
entry.mu.Lock()
- delete(c.cache.table, entry.addr)
- c.cache.lru.Remove(entry)
+ delete(c.mu.table, entry.mu.addr)
+ c.mu.lru.Remove(entry)
// Wake waiters and mark the soon-to-be-reused entry as expired.
entry.notifyCompletionLocked("" /* linkAddr */)
@@ -188,53 +188,55 @@ func (c *linkAddrCache) getOrCreateEntryLocked(k tcpip.Address) *linkAddrEntry {
*entry = linkAddrEntry{
cache: c,
- addr: k,
- s: incomplete,
}
- c.cache.table[k] = entry
- c.cache.lru.PushFront(entry)
+ entry.mu.Lock()
+ entry.mu.addr = k
+ entry.mu.s = incomplete
+ entry.mu.Unlock()
+ c.mu.table[k] = entry
+ c.mu.lru.PushFront(entry)
return entry
}
-// get reports any known link address for k.
-func (c *linkAddrCache) get(k tcpip.Address, linkRes LinkAddressResolver, localAddr tcpip.Address, nic NetworkInterface, onResolve func(LinkResolutionResult)) (tcpip.LinkAddress, <-chan struct{}, *tcpip.Error) {
- c.cache.Lock()
- defer c.cache.Unlock()
- entry := c.getOrCreateEntryLocked(k)
+// get reports any known link address for addr.
+func (c *linkAddrCache) get(addr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (tcpip.LinkAddress, <-chan struct{}, tcpip.Error) {
+ c.mu.Lock()
+ entry := c.getOrCreateEntryLocked(addr)
entry.mu.Lock()
defer entry.mu.Unlock()
+ c.mu.Unlock()
- switch s := entry.s; s {
+ switch s := entry.mu.s; s {
case ready:
- if !time.Now().After(entry.expiration) {
+ if !time.Now().After(entry.mu.expiration) {
// Not expired.
if onResolve != nil {
- onResolve(LinkResolutionResult{LinkAddress: entry.linkAddr, Success: true})
+ onResolve(LinkResolutionResult{LinkAddress: entry.mu.linkAddr, Success: true})
}
- return entry.linkAddr, nil, nil
+ return entry.mu.linkAddr, nil, nil
}
entry.changeStateLocked(incomplete, time.Time{})
fallthrough
case incomplete:
if onResolve != nil {
- entry.onResolve = append(entry.onResolve, onResolve)
+ entry.mu.onResolve = append(entry.mu.onResolve, onResolve)
}
- if entry.done == nil {
- entry.done = make(chan struct{})
- go c.startAddressResolution(k, linkRes, localAddr, nic, entry.done) // S/R-SAFE: link non-savable; wakers dropped synchronously.
+ if entry.mu.done == nil {
+ entry.mu.done = make(chan struct{})
+ go c.startAddressResolution(addr, localAddr, entry.mu.done) // S/R-SAFE: link non-savable; wakers dropped synchronously.
}
- return entry.linkAddr, entry.done, tcpip.ErrWouldBlock
+ return entry.mu.linkAddr, entry.mu.done, &tcpip.ErrWouldBlock{}
default:
panic(fmt.Sprintf("invalid cache entry state: %s", s))
}
}
-func (c *linkAddrCache) startAddressResolution(k tcpip.Address, linkRes LinkAddressResolver, localAddr tcpip.Address, nic NetworkInterface, done <-chan struct{}) {
+func (c *linkAddrCache) startAddressResolution(k tcpip.Address, localAddr tcpip.Address, done <-chan struct{}) {
for i := 0; ; i++ {
// Send link request, then wait for the timeout limit and check
// whether the request succeeded.
- linkRes.LinkAddressRequest(k, localAddr, "" /* linkAddr */, nic)
+ c.linkRes.LinkAddressRequest(k, localAddr, "" /* linkAddr */)
select {
case now := <-time.After(c.resolutionTimeout):
@@ -251,9 +253,9 @@ func (c *linkAddrCache) startAddressResolution(k tcpip.Address, linkRes LinkAddr
// succeeded and mark the entry accordingly. Returns true if request can stop,
// false if another request should be sent.
func (c *linkAddrCache) checkLinkRequest(now time.Time, k tcpip.Address, attempt int) bool {
- c.cache.Lock()
- defer c.cache.Unlock()
- entry, ok := c.cache.table[k]
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ entry, ok := c.mu.table[k]
if !ok {
// Entry was evicted from the cache.
return true
@@ -261,7 +263,7 @@ func (c *linkAddrCache) checkLinkRequest(now time.Time, k tcpip.Address, attempt
entry.mu.Lock()
defer entry.mu.Unlock()
- switch s := entry.s; s {
+ switch s := entry.mu.s; s {
case ready:
// Entry was made ready by resolver.
case incomplete:
@@ -271,20 +273,87 @@ func (c *linkAddrCache) checkLinkRequest(now time.Time, k tcpip.Address, attempt
}
// Max number of retries reached, delete entry.
entry.notifyCompletionLocked("" /* linkAddr */)
- delete(c.cache.table, k)
+ delete(c.mu.table, k)
default:
panic(fmt.Sprintf("invalid cache entry state: %s", s))
}
return true
}
-func newLinkAddrCache(nic *NIC, ageLimit, resolutionTimeout time.Duration, resolutionAttempts int) *linkAddrCache {
- c := &linkAddrCache{
+func (c *linkAddrCache) init(nic *NIC, ageLimit, resolutionTimeout time.Duration, resolutionAttempts int, linkRes LinkAddressResolver) {
+ *c = linkAddrCache{
nic: nic,
+ linkRes: linkRes,
ageLimit: ageLimit,
resolutionTimeout: resolutionTimeout,
resolutionAttempts: resolutionAttempts,
}
- c.cache.table = make(map[tcpip.Address]*linkAddrEntry, linkAddrCacheSize)
- return c
+
+ c.mu.Lock()
+ c.mu.table = make(map[tcpip.Address]*linkAddrEntry, linkAddrCacheSize)
+ c.mu.Unlock()
+}
+
+var _ neighborTable = (*linkAddrCache)(nil)
+
+func (*linkAddrCache) neighbors() ([]NeighborEntry, tcpip.Error) {
+ return nil, &tcpip.ErrNotSupported{}
+}
+
+func (c *linkAddrCache) addStaticEntry(addr tcpip.Address, linkAddr tcpip.LinkAddress) {
+ c.add(addr, linkAddr)
+}
+
+func (*linkAddrCache) remove(addr tcpip.Address) tcpip.Error {
+ return &tcpip.ErrNotSupported{}
+}
+
+func (*linkAddrCache) removeAll() tcpip.Error {
+ return &tcpip.ErrNotSupported{}
+}
+
+func (c *linkAddrCache) handleProbe(addr tcpip.Address, linkAddr tcpip.LinkAddress) {
+ if len(linkAddr) != 0 {
+ // NUD allows probes without a link address but linkAddrCache
+ // is a simple neighbor table which does not implement NUD.
+ //
+ // As per RFC 4861 section 4.3,
+ //
+ // Source link-layer address
+ // The link-layer address for the sender. MUST NOT be
+ // included when the source IP address is the
+ // unspecified address. Otherwise, on link layers
+ // that have addresses this option MUST be included in
+ // multicast solicitations and SHOULD be included in
+ // unicast solicitations.
+ c.add(addr, linkAddr)
+ }
+}
+
+func (c *linkAddrCache) handleConfirmation(addr tcpip.Address, linkAddr tcpip.LinkAddress, flags ReachabilityConfirmationFlags) {
+ if len(linkAddr) != 0 {
+ // NUD allows confirmations without a link address but linkAddrCache
+ // is a simple neighbor table which does not implement NUD.
+ //
+ // As per RFC 4861 section 4.4,
+ //
+ // Target link-layer address
+ // The link-layer address for the target, i.e., the
+ // sender of the advertisement. This option MUST be
+ // included on link layers that have addresses when
+ // responding to multicast solicitations. When
+ // responding to a unicast Neighbor Solicitation this
+ // option SHOULD be included.
+ c.add(addr, linkAddr)
+ }
+}
+
+func (c *linkAddrCache) handleUpperLevelConfirmation(tcpip.Address) {}
+
+func (*linkAddrCache) nudConfig() (NUDConfigurations, tcpip.Error) {
+ return NUDConfigurations{}, &tcpip.ErrNotSupported{}
+}
+
+func (*linkAddrCache) setNUDConfig(NUDConfigurations) tcpip.Error {
+ return &tcpip.ErrNotSupported{}
}
diff --git a/pkg/tcpip/stack/linkaddrcache_test.go b/pkg/tcpip/stack/linkaddrcache_test.go
index 88fbbf3fe..9e7f331c9 100644
--- a/pkg/tcpip/stack/linkaddrcache_test.go
+++ b/pkg/tcpip/stack/linkaddrcache_test.go
@@ -48,7 +48,7 @@ type testLinkAddressResolver struct {
onLinkAddressRequest func()
}
-func (r *testLinkAddressResolver) LinkAddressRequest(targetAddr, _ tcpip.Address, _ tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
+func (r *testLinkAddressResolver) LinkAddressRequest(targetAddr, _ tcpip.Address, _ tcpip.LinkAddress) tcpip.Error {
// TODO(gvisor.dev/issue/5141): Use a fake clock.
time.AfterFunc(r.delay, func() { r.fakeRequest(targetAddr) })
if f := r.onLinkAddressRequest; f != nil {
@@ -60,7 +60,7 @@ func (r *testLinkAddressResolver) LinkAddressRequest(targetAddr, _ tcpip.Address
func (r *testLinkAddressResolver) fakeRequest(addr tcpip.Address) {
for _, ta := range testAddrs {
if ta.addr == addr {
- r.cache.AddLinkAddress(ta.addr, ta.linkAddr)
+ r.cache.add(ta.addr, ta.linkAddr)
break
}
}
@@ -77,13 +77,13 @@ func (*testLinkAddressResolver) LinkAddressProtocol() tcpip.NetworkProtocolNumbe
return 1
}
-func getBlocking(c *linkAddrCache, addr tcpip.Address, linkRes LinkAddressResolver) (tcpip.LinkAddress, *tcpip.Error) {
+func getBlocking(c *linkAddrCache, addr tcpip.Address) (tcpip.LinkAddress, tcpip.Error) {
var attemptedResolution bool
for {
- got, ch, err := c.get(addr, linkRes, "", nil, nil)
- if err == tcpip.ErrWouldBlock {
+ got, ch, err := c.get(addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); ok {
if attemptedResolution {
- return got, tcpip.ErrTimeout
+ return got, &tcpip.ErrTimeout{}
}
attemptedResolution = true
<-ch
@@ -100,50 +100,52 @@ func newEmptyNIC() *NIC {
}
func TestCacheOverflow(t *testing.T) {
- c := newLinkAddrCache(newEmptyNIC(), 1<<63-1, 1*time.Second, 3)
+ var c linkAddrCache
+ c.init(newEmptyNIC(), 1<<63-1, 1*time.Second, 3, nil)
for i := len(testAddrs) - 1; i >= 0; i-- {
e := testAddrs[i]
- c.AddLinkAddress(e.addr, e.linkAddr)
- got, _, err := c.get(e.addr, nil, "", nil, nil)
+ c.add(e.addr, e.linkAddr)
+ got, _, err := c.get(e.addr, "", nil)
if err != nil {
- t.Errorf("insert %d, c.get(%s, nil, '', nil, nil): %s", i, e.addr, err)
+ t.Errorf("insert %d, c.get(%s, '', nil): %s", i, e.addr, err)
}
if got != e.linkAddr {
- t.Errorf("insert %d, got c.get(%s, nil, '', nil, nil) = %s, want = %s", i, e.addr, got, e.linkAddr)
+ t.Errorf("insert %d, got c.get(%s, '', nil) = %s, want = %s", i, e.addr, got, e.linkAddr)
}
}
// Expect to find at least half of the most recent entries.
for i := 0; i < linkAddrCacheSize/2; i++ {
e := testAddrs[i]
- got, _, err := c.get(e.addr, nil, "", nil, nil)
+ got, _, err := c.get(e.addr, "", nil)
if err != nil {
- t.Errorf("check %d, c.get(%s, nil, '', nil, nil): %s", i, e.addr, err)
+ t.Errorf("check %d, c.get(%s, '', nil): %s", i, e.addr, err)
}
if got != e.linkAddr {
- t.Errorf("check %d, got c.get(%s, nil, '', nil, nil) = %s, want = %s", i, e.addr, got, e.linkAddr)
+ t.Errorf("check %d, got c.get(%s, '', nil) = %s, want = %s", i, e.addr, got, e.linkAddr)
}
}
// The earliest entries should no longer be in the cache.
- c.cache.Lock()
- defer c.cache.Unlock()
+ c.mu.Lock()
+ defer c.mu.Unlock()
for i := len(testAddrs) - 1; i >= len(testAddrs)-linkAddrCacheSize; i-- {
e := testAddrs[i]
- if entry, ok := c.cache.table[e.addr]; ok {
- t.Errorf("unexpected entry at c.cache.table[%s]: %#v", e.addr, entry)
+ if entry, ok := c.mu.table[e.addr]; ok {
+ t.Errorf("unexpected entry at c.mu.table[%s]: %#v", e.addr, entry)
}
}
}
func TestCacheConcurrent(t *testing.T) {
- c := newLinkAddrCache(newEmptyNIC(), 1<<63-1, 1*time.Second, 3)
- linkRes := &testLinkAddressResolver{cache: c}
+ var c linkAddrCache
+ linkRes := &testLinkAddressResolver{cache: &c}
+ c.init(newEmptyNIC(), 1<<63-1, 1*time.Second, 3, linkRes)
var wg sync.WaitGroup
for r := 0; r < 16; r++ {
wg.Add(1)
go func() {
for _, e := range testAddrs {
- c.AddLinkAddress(e.addr, e.linkAddr)
+ c.add(e.addr, e.linkAddr)
}
wg.Done()
}()
@@ -154,54 +156,57 @@ func TestCacheConcurrent(t *testing.T) {
// can fit in the cache, so our eviction strategy requires that
// the last entry be present and the first be missing.
e := testAddrs[len(testAddrs)-1]
- got, _, err := c.get(e.addr, linkRes, "", nil, nil)
+ got, _, err := c.get(e.addr, "", nil)
if err != nil {
- t.Errorf("c.get(%s, _, '', nil, nil): %s", e.addr, err)
+ t.Errorf("c.get(%s, '', nil): %s", e.addr, err)
}
if got != e.linkAddr {
- t.Errorf("got c.get(%s, _, '', nil, nil) = %s, want = %s", e.addr, got, e.linkAddr)
+ t.Errorf("got c.get(%s, '', nil) = %s, want = %s", e.addr, got, e.linkAddr)
}
e = testAddrs[0]
- c.cache.Lock()
- defer c.cache.Unlock()
- if entry, ok := c.cache.table[e.addr]; ok {
- t.Errorf("unexpected entry at c.cache.table[%s]: %#v", e.addr, entry)
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if entry, ok := c.mu.table[e.addr]; ok {
+ t.Errorf("unexpected entry at c.mu.table[%s]: %#v", e.addr, entry)
}
}
func TestCacheAgeLimit(t *testing.T) {
- c := newLinkAddrCache(newEmptyNIC(), 1*time.Millisecond, 1*time.Second, 3)
- linkRes := &testLinkAddressResolver{cache: c}
+ var c linkAddrCache
+ linkRes := &testLinkAddressResolver{cache: &c}
+ c.init(newEmptyNIC(), 1*time.Millisecond, 1*time.Second, 3, linkRes)
e := testAddrs[0]
- c.AddLinkAddress(e.addr, e.linkAddr)
+ c.add(e.addr, e.linkAddr)
time.Sleep(50 * time.Millisecond)
- if _, _, err := c.get(e.addr, linkRes, "", nil, nil); err != tcpip.ErrWouldBlock {
- t.Errorf("got c.get(%s, _, '', nil, nil) = %s, want = ErrWouldBlock", e.addr, err)
+ _, _, err := c.get(e.addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got c.get(%s, '', nil) = %s, want = ErrWouldBlock", e.addr, err)
}
}
func TestCacheReplace(t *testing.T) {
- c := newLinkAddrCache(newEmptyNIC(), 1<<63-1, 1*time.Second, 3)
+ var c linkAddrCache
+ c.init(newEmptyNIC(), 1<<63-1, 1*time.Second, 3, nil)
e := testAddrs[0]
l2 := e.linkAddr + "2"
- c.AddLinkAddress(e.addr, e.linkAddr)
- got, _, err := c.get(e.addr, nil, "", nil, nil)
+ c.add(e.addr, e.linkAddr)
+ got, _, err := c.get(e.addr, "", nil)
if err != nil {
- t.Errorf("c.get(%s, nil, '', nil, nil): %s", e.addr, err)
+ t.Errorf("c.get(%s, '', nil): %s", e.addr, err)
}
if got != e.linkAddr {
- t.Errorf("got c.get(%s, nil, '', nil, nil) = %s, want = %s", e.addr, got, e.linkAddr)
+ t.Errorf("got c.get(%s, '', nil) = %s, want = %s", e.addr, got, e.linkAddr)
}
- c.AddLinkAddress(e.addr, l2)
- got, _, err = c.get(e.addr, nil, "", nil, nil)
+ c.add(e.addr, l2)
+ got, _, err = c.get(e.addr, "", nil)
if err != nil {
- t.Errorf("c.get(%s, nil, '', nil, nil): %s", e.addr, err)
+ t.Errorf("c.get(%s, '', nil): %s", e.addr, err)
}
if got != l2 {
- t.Errorf("got c.get(%s, nil, '', nil, nil) = %s, want = %s", e.addr, got, l2)
+ t.Errorf("got c.get(%s, '', nil) = %s, want = %s", e.addr, got, l2)
}
}
@@ -212,34 +217,36 @@ func TestCacheResolution(t *testing.T) {
//
// Using a large resolution timeout decreases the probability of experiencing
// this race condition and does not affect how long this test takes to run.
- c := newLinkAddrCache(newEmptyNIC(), 1<<63-1, math.MaxInt64, 1)
- linkRes := &testLinkAddressResolver{cache: c}
+ var c linkAddrCache
+ linkRes := &testLinkAddressResolver{cache: &c}
+ c.init(newEmptyNIC(), 1<<63-1, math.MaxInt64, 1, linkRes)
for i, ta := range testAddrs {
- got, err := getBlocking(c, ta.addr, linkRes)
+ got, err := getBlocking(&c, ta.addr)
if err != nil {
- t.Errorf("check %d, getBlocking(_, %s, _): %s", i, ta.addr, err)
+ t.Errorf("check %d, getBlocking(_, %s): %s", i, ta.addr, err)
}
if got != ta.linkAddr {
- t.Errorf("check %d, got getBlocking(_, %s, _) = %s, want = %s", i, ta.addr, got, ta.linkAddr)
+ t.Errorf("check %d, got getBlocking(_, %s) = %s, want = %s", i, ta.addr, got, ta.linkAddr)
}
}
// Check that after resolved, address stays in the cache and never returns WouldBlock.
for i := 0; i < 10; i++ {
e := testAddrs[len(testAddrs)-1]
- got, _, err := c.get(e.addr, linkRes, "", nil, nil)
+ got, _, err := c.get(e.addr, "", nil)
if err != nil {
- t.Errorf("c.get(%s, _, '', nil, nil): %s", e.addr, err)
+ t.Errorf("c.get(%s, '', nil): %s", e.addr, err)
}
if got != e.linkAddr {
- t.Errorf("got c.get(%s, _, '', nil, nil) = %s, want = %s", e.addr, got, e.linkAddr)
+ t.Errorf("got c.get(%s, '', nil) = %s, want = %s", e.addr, got, e.linkAddr)
}
}
}
func TestCacheResolutionFailed(t *testing.T) {
- c := newLinkAddrCache(newEmptyNIC(), 1<<63-1, 10*time.Millisecond, 5)
- linkRes := &testLinkAddressResolver{cache: c}
+ var c linkAddrCache
+ linkRes := &testLinkAddressResolver{cache: &c}
+ c.init(newEmptyNIC(), 1<<63-1, 10*time.Millisecond, 5, linkRes)
var requestCount uint32
linkRes.onLinkAddressRequest = func() {
@@ -248,19 +255,20 @@ func TestCacheResolutionFailed(t *testing.T) {
// First, sanity check that resolution is working...
e := testAddrs[0]
- got, err := getBlocking(c, e.addr, linkRes)
+ got, err := getBlocking(&c, e.addr)
if err != nil {
- t.Errorf("getBlocking(_, %s, _): %s", e.addr, err)
+ t.Errorf("getBlocking(_, %s): %s", e.addr, err)
}
if got != e.linkAddr {
- t.Errorf("got getBlocking(_, %s, _) = %s, want = %s", e.addr, got, e.linkAddr)
+ t.Errorf("got getBlocking(_, %s) = %s, want = %s", e.addr, got, e.linkAddr)
}
before := atomic.LoadUint32(&requestCount)
e.addr += "2"
- if a, err := getBlocking(c, e.addr, linkRes); err != tcpip.ErrTimeout {
- t.Errorf("got getBlocking(_, %s, _) = (%s, %s), want = (_, %s)", e.addr, a, err, tcpip.ErrTimeout)
+ a, err := getBlocking(&c, e.addr)
+ if _, ok := err.(*tcpip.ErrTimeout); !ok {
+ t.Errorf("got getBlocking(_, %s) = (%s, %s), want = (_, %s)", e.addr, a, err, &tcpip.ErrTimeout{})
}
if got, want := int(atomic.LoadUint32(&requestCount)-before), c.resolutionAttempts; got != want {
@@ -271,11 +279,13 @@ func TestCacheResolutionFailed(t *testing.T) {
func TestCacheResolutionTimeout(t *testing.T) {
resolverDelay := 500 * time.Millisecond
expiration := resolverDelay / 10
- c := newLinkAddrCache(newEmptyNIC(), expiration, 1*time.Millisecond, 3)
- linkRes := &testLinkAddressResolver{cache: c, delay: resolverDelay}
+ var c linkAddrCache
+ linkRes := &testLinkAddressResolver{cache: &c, delay: resolverDelay}
+ c.init(newEmptyNIC(), expiration, 1*time.Millisecond, 3, linkRes)
e := testAddrs[0]
- if a, err := getBlocking(c, e.addr, linkRes); err != tcpip.ErrTimeout {
- t.Errorf("got getBlocking(_, %s, _) = (%s, %s), want = (_, %s)", e.addr, a, err, tcpip.ErrTimeout)
+ a, err := getBlocking(&c, e.addr)
+ if _, ok := err.(*tcpip.ErrTimeout); !ok {
+ t.Errorf("got getBlocking(_, %s) = (%s, %s), want = (_, %s)", e.addr, a, err, &tcpip.ErrTimeout{})
}
}
diff --git a/pkg/tcpip/stack/ndp_test.go b/pkg/tcpip/stack/ndp_test.go
index d7bbb25ea..0238605af 100644
--- a/pkg/tcpip/stack/ndp_test.go
+++ b/pkg/tcpip/stack/ndp_test.go
@@ -104,7 +104,7 @@ type ndpDADEvent struct {
nicID tcpip.NICID
addr tcpip.Address
resolved bool
- err *tcpip.Error
+ err tcpip.Error
}
type ndpRouterEvent struct {
@@ -174,7 +174,7 @@ type ndpDispatcher struct {
}
// Implements ipv6.NDPDispatcher.OnDuplicateAddressDetectionStatus.
-func (n *ndpDispatcher) OnDuplicateAddressDetectionStatus(nicID tcpip.NICID, addr tcpip.Address, resolved bool, err *tcpip.Error) {
+func (n *ndpDispatcher) OnDuplicateAddressDetectionStatus(nicID tcpip.NICID, addr tcpip.Address, resolved bool, err tcpip.Error) {
if n.dadC != nil {
n.dadC <- ndpDADEvent{
nicID,
@@ -311,7 +311,7 @@ func (l *channelLinkWithHeaderLength) MaxHeaderLength() uint16 {
// Check e to make sure that the event is for addr on nic with ID 1, and the
// resolved flag set to resolved with the specified err.
-func checkDADEvent(e ndpDADEvent, nicID tcpip.NICID, addr tcpip.Address, resolved bool, err *tcpip.Error) string {
+func checkDADEvent(e ndpDADEvent, nicID tcpip.NICID, addr tcpip.Address, resolved bool, err tcpip.Error) string {
return cmp.Diff(ndpDADEvent{nicID: nicID, addr: addr, resolved: resolved, err: err}, e, cmp.AllowUnexported(e))
}
@@ -465,8 +465,8 @@ func TestDADResolve(t *testing.T) {
// tentative address.
{
r, err := s.FindRoute(nicID, "", addr2, header.IPv6ProtocolNumber, false)
- if err != tcpip.ErrNoRoute {
- t.Errorf("got FindRoute(%d, '', %s, %d, false) = (%+v, %v), want = (_, %s)", nicID, addr2, header.IPv6ProtocolNumber, r, err, tcpip.ErrNoRoute)
+ if _, ok := err.(*tcpip.ErrNoRoute); !ok {
+ t.Errorf("got FindRoute(%d, '', %s, %d, false) = (%+v, %v), want = (_, %s)", nicID, addr2, header.IPv6ProtocolNumber, r, err, &tcpip.ErrNoRoute{})
}
if r != nil {
r.Release()
@@ -474,8 +474,8 @@ func TestDADResolve(t *testing.T) {
}
{
r, err := s.FindRoute(nicID, addr1, addr2, header.IPv6ProtocolNumber, false)
- if err != tcpip.ErrNoRoute {
- t.Errorf("got FindRoute(%d, %s, %s, %d, false) = (%+v, %v), want = (_, %s)", nicID, addr1, addr2, header.IPv6ProtocolNumber, r, err, tcpip.ErrNoRoute)
+ if _, ok := err.(*tcpip.ErrNoRoute); !ok {
+ t.Errorf("got FindRoute(%d, %s, %s, %d, false) = (%+v, %v), want = (_, %s)", nicID, addr1, addr2, header.IPv6ProtocolNumber, r, err, &tcpip.ErrNoRoute{})
}
if r != nil {
r.Release()
@@ -2796,14 +2796,8 @@ func stackAndNdpDispatcherWithDefaultRoute(t *testing.T, nicID tcpip.NICID, useN
NIC: nicID,
}})
- if useNeighborCache {
- if err := s.AddStaticNeighbor(nicID, llAddr3, linkAddr3); err != nil {
- t.Fatalf("s.AddStaticNeighbor(%d, %s, %s): %s", nicID, llAddr3, linkAddr3, err)
- }
- } else {
- if err := s.AddLinkAddress(nicID, llAddr3, linkAddr3); err != nil {
- t.Fatalf("s.AddLinkAddress(%d, %s, %s): %s", nicID, llAddr3, linkAddr3, err)
- }
+ if err := s.AddStaticNeighbor(nicID, ipv6.ProtocolNumber, llAddr3, linkAddr3); err != nil {
+ t.Fatalf("s.AddStaticNeighbor(%d, %d, %s, %s): %s", nicID, ipv6.ProtocolNumber, llAddr3, linkAddr3, err)
}
return ndpDisp, e, s
}
@@ -3222,8 +3216,11 @@ func TestAutoGenAddrJobDeprecation(t *testing.T) {
defer ep.Close()
ep.SocketOptions().SetV6Only(true)
- if err := ep.Connect(dstAddr); err != tcpip.ErrNoRoute {
- t.Errorf("got ep.Connect(%+v) = %s, want = %s", dstAddr, err, tcpip.ErrNoRoute)
+ {
+ err := ep.Connect(dstAddr)
+ if _, ok := err.(*tcpip.ErrNoRoute); !ok {
+ t.Errorf("got ep.Connect(%+v) = %s, want = %s", dstAddr, err, &tcpip.ErrNoRoute{})
+ }
}
})
}
diff --git a/pkg/tcpip/stack/neighbor_cache.go b/pkg/tcpip/stack/neighbor_cache.go
index 204196d00..7e3132058 100644
--- a/pkg/tcpip/stack/neighbor_cache.go
+++ b/pkg/tcpip/stack/neighbor_cache.go
@@ -42,11 +42,10 @@ type NeighborStats struct {
// 2. Static entries are explicitly added by a user and have no expiration.
// Their state is always Static. The amount of static entries stored in the
// cache is unbounded.
-//
-// neighborCache implements NUDHandler.
type neighborCache struct {
- nic *NIC
- state *NUDState
+ nic *NIC
+ state *NUDState
+ linkRes LinkAddressResolver
// mu protects the fields below.
mu sync.RWMutex
@@ -62,8 +61,6 @@ type neighborCache struct {
}
}
-var _ NUDHandler = (*neighborCache)(nil)
-
// getOrCreateEntry retrieves a cache entry associated with addr. The
// returned entry is always refreshed in the cache (it is reachable via the
// map, and its place is bumped in LRU).
@@ -73,7 +70,7 @@ var _ NUDHandler = (*neighborCache)(nil)
// reset to state incomplete, and returned. If no matching entry exists and the
// cache is not full, a new entry with state incomplete is allocated and
// returned.
-func (n *neighborCache) getOrCreateEntry(remoteAddr tcpip.Address, linkRes LinkAddressResolver) *neighborEntry {
+func (n *neighborCache) getOrCreateEntry(remoteAddr tcpip.Address) *neighborEntry {
n.mu.Lock()
defer n.mu.Unlock()
@@ -89,7 +86,7 @@ func (n *neighborCache) getOrCreateEntry(remoteAddr tcpip.Address, linkRes LinkA
// The entry that needs to be created must be dynamic since all static
// entries are directly added to the cache via addStaticEntry.
- entry := newNeighborEntry(n.nic, remoteAddr, n.state, linkRes)
+ entry := newNeighborEntry(n, remoteAddr, n.state)
if n.dynamic.count == neighborCacheSize {
e := n.dynamic.lru.Back()
e.mu.Lock()
@@ -126,8 +123,8 @@ func (n *neighborCache) getOrCreateEntry(remoteAddr tcpip.Address, linkRes LinkA
// packet prompting NUD/link address resolution.
//
// TODO(gvisor.dev/issue/5151): Don't return the neighbor entry.
-func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, linkRes LinkAddressResolver, onResolve func(LinkResolutionResult)) (NeighborEntry, <-chan struct{}, *tcpip.Error) {
- entry := n.getOrCreateEntry(remoteAddr, linkRes)
+func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (NeighborEntry, <-chan struct{}, tcpip.Error) {
+ entry := n.getOrCreateEntry(remoteAddr)
entry.mu.Lock()
defer entry.mu.Unlock()
@@ -154,7 +151,7 @@ func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, linkRes LinkA
entry.done = make(chan struct{})
}
entry.handlePacketQueuedLocked(localAddr)
- return entry.neigh, entry.done, tcpip.ErrWouldBlock
+ return entry.neigh, entry.done, &tcpip.ErrWouldBlock{}
default:
panic(fmt.Sprintf("Invalid cache entry state: %s", s))
}
@@ -206,7 +203,7 @@ func (n *neighborCache) addStaticEntry(addr tcpip.Address, linkAddr tcpip.LinkAd
entry.mu.Unlock()
}
- n.cache[addr] = newStaticNeighborEntry(n.nic, addr, linkAddr, n.state)
+ n.cache[addr] = newStaticNeighborEntry(n, addr, linkAddr, n.state)
}
// removeEntry removes a dynamic or static entry by address from the neighbor
@@ -263,27 +260,45 @@ func (n *neighborCache) setConfig(config NUDConfigurations) {
n.state.SetConfig(config)
}
-// HandleProbe implements NUDHandler.HandleProbe by following the logic defined
-// in RFC 4861 section 7.2.3. Validation of the probe is expected to be handled
-// by the caller.
-func (n *neighborCache) HandleProbe(remoteAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, linkRes LinkAddressResolver) {
- entry := n.getOrCreateEntry(remoteAddr, linkRes)
+var _ neighborTable = (*neighborCache)(nil)
+
+func (n *neighborCache) neighbors() ([]NeighborEntry, tcpip.Error) {
+ return n.entries(), nil
+}
+
+func (n *neighborCache) get(addr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (tcpip.LinkAddress, <-chan struct{}, tcpip.Error) {
+ entry, ch, err := n.entry(addr, localAddr, onResolve)
+ return entry.LinkAddr, ch, err
+}
+
+func (n *neighborCache) remove(addr tcpip.Address) tcpip.Error {
+ if !n.removeEntry(addr) {
+ return &tcpip.ErrBadAddress{}
+ }
+
+ return nil
+}
+
+func (n *neighborCache) removeAll() tcpip.Error {
+ n.clear()
+ return nil
+}
+
+// handleProbe handles a neighbor probe as defined by RFC 4861 section 7.2.3.
+//
+// Validation of the probe is expected to be handled by the caller.
+func (n *neighborCache) handleProbe(remoteAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) {
+ entry := n.getOrCreateEntry(remoteAddr)
entry.mu.Lock()
entry.handleProbeLocked(remoteLinkAddr)
entry.mu.Unlock()
}
-// HandleConfirmation implements NUDHandler.HandleConfirmation by following the
-// logic defined in RFC 4861 section 7.2.5.
+// handleConfirmation handles a neighbor confirmation as defined by
+// RFC 4861 section 7.2.5.
//
-// TODO(gvisor.dev/issue/2277): To protect against ARP poisoning and other
-// attacks against NDP functions, Secure Neighbor Discovery (SEND) Protocol
-// should be deployed where preventing access to the broadcast segment might
-// not be possible. SEND uses RSA key pairs to produce cryptographically
-// generated addresses, as defined in RFC 3972, Cryptographically Generated
-// Addresses (CGA). This ensures that the claimed source of an NDP message is
-// the owner of the claimed address.
-func (n *neighborCache) HandleConfirmation(addr tcpip.Address, linkAddr tcpip.LinkAddress, flags ReachabilityConfirmationFlags) {
+// Validation of the confirmation is expected to be handled by the caller.
+func (n *neighborCache) handleConfirmation(addr tcpip.Address, linkAddr tcpip.LinkAddress, flags ReachabilityConfirmationFlags) {
n.mu.RLock()
entry, ok := n.cache[addr]
n.mu.RUnlock()
@@ -297,10 +312,9 @@ func (n *neighborCache) HandleConfirmation(addr tcpip.Address, linkAddr tcpip.Li
// no matching entry for the remote address.
}
-// HandleUpperLevelConfirmation implements
-// NUDHandler.HandleUpperLevelConfirmation by following the logic defined in
-// RFC 4861 section 7.3.1.
-func (n *neighborCache) HandleUpperLevelConfirmation(addr tcpip.Address) {
+// handleUpperLevelConfirmation processes a confirmation of reachablity from
+// some protocol that operates at a layer above the IP/link layer.
+func (n *neighborCache) handleUpperLevelConfirmation(addr tcpip.Address) {
n.mu.RLock()
entry, ok := n.cache[addr]
n.mu.RUnlock()
@@ -310,3 +324,12 @@ func (n *neighborCache) HandleUpperLevelConfirmation(addr tcpip.Address) {
entry.mu.Unlock()
}
}
+
+func (n *neighborCache) nudConfig() (NUDConfigurations, tcpip.Error) {
+ return n.config(), nil
+}
+
+func (n *neighborCache) setNUDConfig(c NUDConfigurations) tcpip.Error {
+ n.setConfig(c)
+ return nil
+}
diff --git a/pkg/tcpip/stack/neighbor_cache_test.go b/pkg/tcpip/stack/neighbor_cache_test.go
index 6723aef9b..b489b5e08 100644
--- a/pkg/tcpip/stack/neighbor_cache_test.go
+++ b/pkg/tcpip/stack/neighbor_cache_test.go
@@ -76,10 +76,15 @@ func entryDiffOptsWithSort() []cmp.Option {
}))
}
-func newTestNeighborCache(nudDisp NUDDispatcher, config NUDConfigurations, clock tcpip.Clock) *neighborCache {
+func newTestNeighborResolver(nudDisp NUDDispatcher, config NUDConfigurations, clock tcpip.Clock) *testNeighborResolver {
config.resetInvalidFields()
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
- neigh := &neighborCache{
+ linkRes := &testNeighborResolver{
+ clock: clock,
+ entries: newTestEntryStore(),
+ delay: typicalLatency,
+ }
+ linkRes.neigh = &neighborCache{
nic: &NIC{
stack: &Stack{
clock: clock,
@@ -88,11 +93,11 @@ func newTestNeighborCache(nudDisp NUDDispatcher, config NUDConfigurations, clock
id: 1,
stats: makeNICStats(),
},
- state: NewNUDState(config, rng),
- cache: make(map[tcpip.Address]*neighborEntry, neighborCacheSize),
+ state: NewNUDState(config, rng),
+ linkRes: linkRes,
+ cache: make(map[tcpip.Address]*neighborEntry, neighborCacheSize),
}
- neigh.nic.neigh = neigh
- return neigh
+ return linkRes
}
// testEntryStore contains a set of IP to NeighborEntry mappings.
@@ -194,7 +199,7 @@ type testNeighborResolver struct {
var _ LinkAddressResolver = (*testNeighborResolver)(nil)
-func (r *testNeighborResolver) LinkAddressRequest(targetAddr, _ tcpip.Address, _ tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
+func (r *testNeighborResolver) LinkAddressRequest(targetAddr, _ tcpip.Address, _ tcpip.LinkAddress) tcpip.Error {
if !r.dropReplies {
// Delay handling the request to emulate network latency.
r.clock.AfterFunc(r.delay, func() {
@@ -212,7 +217,7 @@ func (r *testNeighborResolver) LinkAddressRequest(targetAddr, _ tcpip.Address, _
// fakeRequest emulates handling a response for a link address request.
func (r *testNeighborResolver) fakeRequest(addr tcpip.Address) {
if entry, ok := r.entries.entryByAddr(addr); ok {
- r.neigh.HandleConfirmation(addr, entry.LinkAddr, ReachabilityConfirmationFlags{
+ r.neigh.handleConfirmation(addr, entry.LinkAddr, ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
IsRouter: false,
@@ -242,17 +247,17 @@ func TestNeighborCacheGetConfig(t *testing.T) {
nudDisp := testNUDDispatcher{}
c := DefaultNUDConfigurations()
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, c, clock)
+ linkRes := newTestNeighborResolver(&nudDisp, c, clock)
- if got, want := neigh.config(), c; got != want {
- t.Errorf("got neigh.config() = %+v, want = %+v", got, want)
+ if got, want := linkRes.neigh.config(), c; got != want {
+ t.Errorf("got linkRes.neigh.config() = %+v, want = %+v", got, want)
}
// No events should have been dispatched.
nudDisp.mu.Lock()
defer nudDisp.mu.Unlock()
- if diff := cmp.Diff(nudDisp.events, []testEntryEventInfo(nil)); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.events); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -260,21 +265,21 @@ func TestNeighborCacheSetConfig(t *testing.T) {
nudDisp := testNUDDispatcher{}
c := DefaultNUDConfigurations()
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, c, clock)
+ linkRes := newTestNeighborResolver(&nudDisp, c, clock)
c.MinRandomFactor = 1
c.MaxRandomFactor = 1
- neigh.setConfig(c)
+ linkRes.neigh.setConfig(c)
- if got, want := neigh.config(), c; got != want {
- t.Errorf("got neigh.config() = %+v, want = %+v", got, want)
+ if got, want := linkRes.neigh.config(), c; got != want {
+ t.Errorf("got linkRes.neigh.config() = %+v, want = %+v", got, want)
}
// No events should have been dispatched.
nudDisp.mu.Lock()
defer nudDisp.mu.Unlock()
- if diff := cmp.Diff(nudDisp.events, []testEntryEventInfo(nil)); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.events); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -282,21 +287,15 @@ func TestNeighborCacheEntry(t *testing.T) {
c := DefaultNUDConfigurations()
nudDisp := testNUDDispatcher{}
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, c, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- }
+ linkRes := newTestNeighborResolver(&nudDisp, c, clock)
- entry, ok := store.entry(0)
+ entry, ok := linkRes.entries.entry(0)
if !ok {
- t.Fatal("store.entry(0) not found")
+ t.Fatal("linkRes.entries.entry(0) not found")
}
- if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
- t.Errorf("got neigh.entry(%s, '', _, nil, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ _, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got linkRes.neigh.entry(%s, '', nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
clock.Advance(typicalLatency)
@@ -321,22 +320,22 @@ func TestNeighborCacheEntry(t *testing.T) {
},
}
nudDisp.mu.Lock()
- diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...)
nudDisp.events = nil
nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
- if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != nil {
- t.Fatalf("unexpected error from neigh.entry(%s, '', _, nil, nil): %s", entry.Addr, err)
+ if _, _, err := linkRes.neigh.entry(entry.Addr, "", nil); err != nil {
+ t.Fatalf("unexpected error from linkRes.neigh.entry(%s, '', nil): %s", entry.Addr, err)
}
// No more events should have been dispatched.
nudDisp.mu.Lock()
defer nudDisp.mu.Unlock()
- if diff := cmp.Diff(nudDisp.events, []testEntryEventInfo(nil)); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.events); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -345,22 +344,16 @@ func TestNeighborCacheRemoveEntry(t *testing.T) {
nudDisp := testNUDDispatcher{}
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, config, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- }
+ linkRes := newTestNeighborResolver(&nudDisp, config, clock)
- entry, ok := store.entry(0)
+ entry, ok := linkRes.entries.entry(0)
if !ok {
- t.Fatal("store.entry(0) not found")
+ t.Fatal("linkRes.entries.entry(0) not found")
}
- if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
- t.Errorf("got neigh.entry(%s, '', _, nil, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ _, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got linkRes.neigh.entry(%s, '', nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
clock.Advance(typicalLatency)
@@ -385,14 +378,14 @@ func TestNeighborCacheRemoveEntry(t *testing.T) {
},
}
nudDisp.mu.Lock()
- diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...)
nudDisp.events = nil
nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
- neigh.removeEntry(entry.Addr)
+ linkRes.neigh.removeEntry(entry.Addr)
{
wantEvents := []testEntryEventInfo{
@@ -407,22 +400,23 @@ func TestNeighborCacheRemoveEntry(t *testing.T) {
},
}
nudDisp.mu.Lock()
- diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...)
nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
- if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
- t.Errorf("got neigh.entry(%s, '', _, nil, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ {
+ _, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got linkRes.neigh.entry(%s, '', nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
+ }
}
}
type testContext struct {
clock *faketime.ManualClock
- neigh *neighborCache
- store *testEntryStore
linkRes *testNeighborResolver
nudDisp *testNUDDispatcher
}
@@ -430,19 +424,10 @@ type testContext struct {
func newTestContext(c NUDConfigurations) testContext {
nudDisp := &testNUDDispatcher{}
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(nudDisp, c, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- }
+ linkRes := newTestNeighborResolver(nudDisp, c, clock)
return testContext{
clock: clock,
- neigh: neigh,
- store: store,
linkRes: linkRes,
nudDisp: nudDisp,
}
@@ -456,16 +441,17 @@ type overflowOptions struct {
func (c *testContext) overflowCache(opts overflowOptions) error {
// Fill the neighbor cache to capacity to verify the LRU eviction strategy is
// working properly after the entry removal.
- for i := opts.startAtEntryIndex; i < c.store.size(); i++ {
+ for i := opts.startAtEntryIndex; i < c.linkRes.entries.size(); i++ {
// Add a new entry
- entry, ok := c.store.entry(i)
+ entry, ok := c.linkRes.entries.entry(i)
if !ok {
- return fmt.Errorf("c.store.entry(%d) not found", i)
+ return fmt.Errorf("c.linkRes.entries.entry(%d) not found", i)
}
- if _, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil); err != tcpip.ErrWouldBlock {
- return fmt.Errorf("got c.neigh.entry(%s, '', _, nil, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ _, _, err := c.linkRes.neigh.entry(entry.Addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ return fmt.Errorf("got c.linkRes.neigh.entry(%s, '', nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
- c.clock.Advance(c.neigh.config().RetransmitTimer)
+ c.clock.Advance(c.linkRes.neigh.config().RetransmitTimer)
var wantEvents []testEntryEventInfo
@@ -473,9 +459,9 @@ func (c *testContext) overflowCache(opts overflowOptions) error {
// LRU eviction strategy. Note that the number of static entries should not
// affect the total number of dynamic entries that can be added.
if i >= neighborCacheSize+opts.startAtEntryIndex {
- removedEntry, ok := c.store.entry(i - neighborCacheSize)
+ removedEntry, ok := c.linkRes.entries.entry(i - neighborCacheSize)
if !ok {
- return fmt.Errorf("store.entry(%d) not found", i-neighborCacheSize)
+ return fmt.Errorf("linkRes.entries.entry(%d) not found", i-neighborCacheSize)
}
wantEvents = append(wantEvents, testEntryEventInfo{
EventType: entryTestRemoved,
@@ -506,11 +492,11 @@ func (c *testContext) overflowCache(opts overflowOptions) error {
})
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- return fmt.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -518,10 +504,10 @@ func (c *testContext) overflowCache(opts overflowOptions) error {
// by entries() is nondeterministic, so entries have to be sorted before
// comparison.
wantUnsortedEntries := opts.wantStaticEntries
- for i := c.store.size() - neighborCacheSize; i < c.store.size(); i++ {
- entry, ok := c.store.entry(i)
+ for i := c.linkRes.entries.size() - neighborCacheSize; i < c.linkRes.entries.size(); i++ {
+ entry, ok := c.linkRes.entries.entry(i)
if !ok {
- return fmt.Errorf("c.store.entry(%d) not found", i)
+ return fmt.Errorf("c.linkRes.entries.entry(%d) not found", i)
}
wantEntry := NeighborEntry{
Addr: entry.Addr,
@@ -531,15 +517,15 @@ func (c *testContext) overflowCache(opts overflowOptions) error {
wantUnsortedEntries = append(wantUnsortedEntries, wantEntry)
}
- if diff := cmp.Diff(c.neigh.entries(), wantUnsortedEntries, entryDiffOptsWithSort()...); diff != "" {
- return fmt.Errorf("neighbor entries mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantUnsortedEntries, c.linkRes.neigh.entries(), entryDiffOptsWithSort()...); diff != "" {
+ return fmt.Errorf("neighbor entries mismatch (-want, +got):\n%s", diff)
}
// No more events should have been dispatched.
c.nudDisp.mu.Lock()
defer c.nudDisp.mu.Unlock()
- if diff := cmp.Diff(c.nudDisp.events, []testEntryEventInfo(nil)); diff != "" {
- return fmt.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff([]testEntryEventInfo(nil), c.nudDisp.events); diff != "" {
+ return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
return nil
@@ -575,14 +561,15 @@ func TestNeighborCacheRemoveEntryThenOverflow(t *testing.T) {
c := newTestContext(config)
// Add a dynamic entry
- entry, ok := c.store.entry(0)
+ entry, ok := c.linkRes.entries.entry(0)
if !ok {
- t.Fatal("c.store.entry(0) not found")
+ t.Fatal("c.linkRes.entries.entry(0) not found")
}
- if _, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil); err != tcpip.ErrWouldBlock {
- t.Errorf("got c.neigh.entry(%s, '', _, nil, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ _, _, err := c.linkRes.neigh.entry(entry.Addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got c.linkRes.neigh.entry(%s, '', nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
- c.clock.Advance(c.neigh.config().RetransmitTimer)
+ c.clock.Advance(c.linkRes.neigh.config().RetransmitTimer)
wantEvents := []testEntryEventInfo{
{
EventType: entryTestAdded,
@@ -603,15 +590,15 @@ func TestNeighborCacheRemoveEntryThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
// Remove the entry
- c.neigh.removeEntry(entry.Addr)
+ c.linkRes.neigh.removeEntry(entry.Addr)
{
wantEvents := []testEntryEventInfo{
@@ -626,11 +613,11 @@ func TestNeighborCacheRemoveEntryThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -650,12 +637,12 @@ func TestNeighborCacheDuplicateStaticEntryWithSameLinkAddress(t *testing.T) {
c := newTestContext(config)
// Add a static entry
- entry, ok := c.store.entry(0)
+ entry, ok := c.linkRes.entries.entry(0)
if !ok {
- t.Fatal("c.store.entry(0) not found")
+ t.Fatal("c.linkRes.entries.entry(0) not found")
}
staticLinkAddr := entry.LinkAddr + "static"
- c.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
+ c.linkRes.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
wantEvents := []testEntryEventInfo{
{
EventType: entryTestAdded,
@@ -668,21 +655,21 @@ func TestNeighborCacheDuplicateStaticEntryWithSameLinkAddress(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
// Remove the static entry that was just added
- c.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
+ c.linkRes.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
// No more events should have been dispatched.
c.nudDisp.mu.Lock()
defer c.nudDisp.mu.Unlock()
- if diff := cmp.Diff(c.nudDisp.events, []testEntryEventInfo(nil)); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff([]testEntryEventInfo(nil), c.nudDisp.events); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -694,12 +681,12 @@ func TestNeighborCacheDuplicateStaticEntryWithDifferentLinkAddress(t *testing.T)
c := newTestContext(config)
// Add a static entry
- entry, ok := c.store.entry(0)
+ entry, ok := c.linkRes.entries.entry(0)
if !ok {
- t.Fatal("c.store.entry(0) not found")
+ t.Fatal("c.linkRes.entries.entry(0) not found")
}
staticLinkAddr := entry.LinkAddr + "static"
- c.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
+ c.linkRes.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
wantEvents := []testEntryEventInfo{
{
EventType: entryTestAdded,
@@ -712,16 +699,16 @@ func TestNeighborCacheDuplicateStaticEntryWithDifferentLinkAddress(t *testing.T)
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
// Add a duplicate entry with a different link address
staticLinkAddr += "duplicate"
- c.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
+ c.linkRes.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
{
wantEvents := []testEntryEventInfo{
{
@@ -736,8 +723,8 @@ func TestNeighborCacheDuplicateStaticEntryWithDifferentLinkAddress(t *testing.T)
}
c.nudDisp.mu.Lock()
defer c.nudDisp.mu.Unlock()
- if diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
}
@@ -756,12 +743,12 @@ func TestNeighborCacheRemoveStaticEntryThenOverflow(t *testing.T) {
c := newTestContext(config)
// Add a static entry
- entry, ok := c.store.entry(0)
+ entry, ok := c.linkRes.entries.entry(0)
if !ok {
- t.Fatal("c.store.entry(0) not found")
+ t.Fatal("c.linkRes.entries.entry(0) not found")
}
staticLinkAddr := entry.LinkAddr + "static"
- c.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
+ c.linkRes.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
wantEvents := []testEntryEventInfo{
{
EventType: entryTestAdded,
@@ -774,15 +761,15 @@ func TestNeighborCacheRemoveStaticEntryThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
// Remove the static entry that was just added
- c.neigh.removeEntry(entry.Addr)
+ c.linkRes.neigh.removeEntry(entry.Addr)
{
wantEvents := []testEntryEventInfo{
{
@@ -796,11 +783,11 @@ func TestNeighborCacheRemoveStaticEntryThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -826,12 +813,13 @@ func TestNeighborCacheOverwriteWithStaticEntryThenOverflow(t *testing.T) {
c := newTestContext(config)
// Add a dynamic entry
- entry, ok := c.store.entry(0)
+ entry, ok := c.linkRes.entries.entry(0)
if !ok {
- t.Fatal("c.store.entry(0) not found")
+ t.Fatal("c.linkRes.entries.entry(0) not found")
}
- if _, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil); err != tcpip.ErrWouldBlock {
- t.Errorf("got c.neigh.entry(%s, '', _, nil, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ _, _, err := c.linkRes.neigh.entry(entry.Addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got c.linkRes.neigh.entry(%s, '', nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
c.clock.Advance(typicalLatency)
wantEvents := []testEntryEventInfo{
@@ -854,16 +842,16 @@ func TestNeighborCacheOverwriteWithStaticEntryThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
// Override the entry with a static one using the same address
staticLinkAddr := entry.LinkAddr + "static"
- c.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
+ c.linkRes.neigh.addStaticEntry(entry.Addr, staticLinkAddr)
{
wantEvents := []testEntryEventInfo{
{
@@ -886,11 +874,11 @@ func TestNeighborCacheOverwriteWithStaticEntryThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -918,22 +906,22 @@ func TestNeighborCacheAddStaticEntryThenOverflow(t *testing.T) {
c := newTestContext(config)
- entry, ok := c.store.entry(0)
+ entry, ok := c.linkRes.entries.entry(0)
if !ok {
- t.Fatal("c.store.entry(0) not found")
+ t.Fatal("c.linkRes.entries.entry(0) not found")
}
- c.neigh.addStaticEntry(entry.Addr, entry.LinkAddr)
- e, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil)
+ c.linkRes.neigh.addStaticEntry(entry.Addr, entry.LinkAddr)
+ e, _, err := c.linkRes.neigh.entry(entry.Addr, "", nil)
if err != nil {
- t.Errorf("unexpected error from c.neigh.entry(%s, \"\", _, nil, nil): %s", entry.Addr, err)
+ t.Errorf("unexpected error from c.linkRes.neigh.entry(%s, \"\", nil): %s", entry.Addr, err)
}
want := NeighborEntry{
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Static,
}
- if diff := cmp.Diff(e, want, entryDiffOpts()...); diff != "" {
- t.Errorf("c.neigh.entry(%s, \"\", _, nil, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
+ if diff := cmp.Diff(want, e, entryDiffOpts()...); diff != "" {
+ t.Errorf("c.linkRes.neigh.entry(%s, \"\", nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
}
wantEvents := []testEntryEventInfo{
@@ -948,11 +936,11 @@ func TestNeighborCacheAddStaticEntryThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
opts := overflowOptions{
@@ -975,22 +963,16 @@ func TestNeighborCacheClear(t *testing.T) {
nudDisp := testNUDDispatcher{}
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, config, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- }
+ linkRes := newTestNeighborResolver(&nudDisp, config, clock)
// Add a dynamic entry.
- entry, ok := store.entry(0)
+ entry, ok := linkRes.entries.entry(0)
if !ok {
- t.Fatal("store.entry(0) not found")
+ t.Fatal("linkRes.entries.entry(0) not found")
}
- if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
- t.Errorf("got neigh.entry(%s, '', _, nil, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ _, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got linkRes.neigh.entry(%s, '', nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
clock.Advance(typicalLatency)
@@ -1014,15 +996,15 @@ func TestNeighborCacheClear(t *testing.T) {
},
}
nudDisp.mu.Lock()
- diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...)
nudDisp.events = nil
nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
// Add a static entry.
- neigh.addStaticEntry(entryTestAddr1, entryTestLinkAddr1)
+ linkRes.neigh.addStaticEntry(entryTestAddr1, entryTestLinkAddr1)
{
wantEvents := []testEntryEventInfo{
@@ -1037,16 +1019,16 @@ func TestNeighborCacheClear(t *testing.T) {
},
}
nudDisp.mu.Lock()
- diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...)
nudDisp.events = nil
nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
// Clear should remove both dynamic and static entries.
- neigh.clear()
+ linkRes.neigh.clear()
// Remove events dispatched from clear() have no deterministic order so they
// need to be sorted beforehand.
@@ -1072,8 +1054,8 @@ func TestNeighborCacheClear(t *testing.T) {
}
nudDisp.mu.Lock()
defer nudDisp.mu.Unlock()
- if diff := cmp.Diff(nudDisp.events, wantUnsortedEvents, eventDiffOptsWithSort()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantUnsortedEvents, nudDisp.events, eventDiffOptsWithSort()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -1090,12 +1072,13 @@ func TestNeighborCacheClearThenOverflow(t *testing.T) {
c := newTestContext(config)
// Add a dynamic entry
- entry, ok := c.store.entry(0)
+ entry, ok := c.linkRes.entries.entry(0)
if !ok {
- t.Fatal("c.store.entry(0) not found")
+ t.Fatal("c.linkRes.entries.entry(0) not found")
}
- if _, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil); err != tcpip.ErrWouldBlock {
- t.Errorf("got c.neigh.entry(%s, '', _, nil, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ _, _, err := c.linkRes.neigh.entry(entry.Addr, "", nil)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got c.linkRes.neigh.entry(%s, '', nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
c.clock.Advance(typicalLatency)
wantEvents := []testEntryEventInfo{
@@ -1118,15 +1101,15 @@ func TestNeighborCacheClearThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
// Clear the cache.
- c.neigh.clear()
+ c.linkRes.neigh.clear()
{
wantEvents := []testEntryEventInfo{
{
@@ -1140,11 +1123,11 @@ func TestNeighborCacheClearThenOverflow(t *testing.T) {
},
}
c.nudDisp.mu.Lock()
- diff := cmp.Diff(c.nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, c.nudDisp.events, eventDiffOpts()...)
c.nudDisp.events = nil
c.nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -1165,18 +1148,11 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
nudDisp := testNUDDispatcher{}
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, config, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- }
+ linkRes := newTestNeighborResolver(&nudDisp, config, clock)
- frequentlyUsedEntry, ok := store.entry(0)
+ frequentlyUsedEntry, ok := linkRes.entries.entry(0)
if !ok {
- t.Fatal("store.entry(0) not found")
+ t.Fatal("linkRes.entries.entry(0) not found")
}
// The following logic is very similar to overflowCache, but
@@ -1184,23 +1160,23 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
// Fill the neighbor cache to capacity
for i := 0; i < neighborCacheSize; i++ {
- entry, ok := store.entry(i)
+ entry, ok := linkRes.entries.entry(i)
if !ok {
- t.Fatalf("store.entry(%d) not found", i)
+ t.Fatalf("linkRes.entries.entry(%d) not found", i)
}
- _, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ _, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{LinkAddress: entry.LinkAddr, Success: true}, r); diff != "" {
t.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- t.Errorf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got linkRes.neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
clock.Advance(typicalLatency)
select {
case <-ch:
default:
- t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ t.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
wantEvents := []testEntryEventInfo{
{
@@ -1222,47 +1198,47 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
},
}
nudDisp.mu.Lock()
- diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...)
nudDisp.events = nil
nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
// Keep adding more entries
- for i := neighborCacheSize; i < store.size(); i++ {
+ for i := neighborCacheSize; i < linkRes.entries.size(); i++ {
// Periodically refresh the frequently used entry
if i%(neighborCacheSize/2) == 0 {
- if _, _, err := neigh.entry(frequentlyUsedEntry.Addr, "", linkRes, nil); err != nil {
- t.Errorf("unexpected error from neigh.entry(%s, '', _, nil, nil): %s", frequentlyUsedEntry.Addr, err)
+ if _, _, err := linkRes.neigh.entry(frequentlyUsedEntry.Addr, "", nil); err != nil {
+ t.Errorf("unexpected error from linkRes.neigh.entry(%s, '', nil): %s", frequentlyUsedEntry.Addr, err)
}
}
- entry, ok := store.entry(i)
+ entry, ok := linkRes.entries.entry(i)
if !ok {
- t.Fatalf("store.entry(%d) not found", i)
+ t.Fatalf("linkRes.entries.entry(%d) not found", i)
}
- _, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ _, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{LinkAddress: entry.LinkAddr, Success: true}, r); diff != "" {
t.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- t.Errorf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Errorf("got linkRes.neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
clock.Advance(typicalLatency)
select {
case <-ch:
default:
- t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ t.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
// An entry should have been removed, as per the LRU eviction strategy
- removedEntry, ok := store.entry(i - neighborCacheSize + 1)
+ removedEntry, ok := linkRes.entries.entry(i - neighborCacheSize + 1)
if !ok {
- t.Fatalf("store.entry(%d) not found", i-neighborCacheSize+1)
+ t.Fatalf("linkRes.entries.entry(%d) not found", i-neighborCacheSize+1)
}
wantEvents := []testEntryEventInfo{
{
@@ -1293,11 +1269,11 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
},
}
nudDisp.mu.Lock()
- diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...)
nudDisp.events = nil
nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -1312,10 +1288,10 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
},
}
- for i := store.size() - neighborCacheSize + 1; i < store.size(); i++ {
- entry, ok := store.entry(i)
+ for i := linkRes.entries.size() - neighborCacheSize + 1; i < linkRes.entries.size(); i++ {
+ entry, ok := linkRes.entries.entry(i)
if !ok {
- t.Fatalf("store.entry(%d) not found", i)
+ t.Fatalf("linkRes.entries.entry(%d) not found", i)
}
wantEntry := NeighborEntry{
Addr: entry.Addr,
@@ -1325,15 +1301,15 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
wantUnsortedEntries = append(wantUnsortedEntries, wantEntry)
}
- if diff := cmp.Diff(neigh.entries(), wantUnsortedEntries, entryDiffOptsWithSort()...); diff != "" {
- t.Errorf("neighbor entries mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantUnsortedEntries, linkRes.neigh.entries(), entryDiffOptsWithSort()...); diff != "" {
+ t.Errorf("neighbor entries mismatch (-want, +got):\n%s", diff)
}
// No more events should have been dispatched.
nudDisp.mu.Lock()
defer nudDisp.mu.Unlock()
- if diff := cmp.Diff(nudDisp.events, []testEntryEventInfo(nil)); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.events); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
@@ -1344,24 +1320,19 @@ func TestNeighborCacheConcurrent(t *testing.T) {
nudDisp := testNUDDispatcher{}
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, config, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- }
+ linkRes := newTestNeighborResolver(&nudDisp, config, clock)
- storeEntries := store.entries()
+ storeEntries := linkRes.entries.entries()
for _, entry := range storeEntries {
var wg sync.WaitGroup
for r := 0; r < concurrentProcesses; r++ {
wg.Add(1)
go func(entry NeighborEntry) {
defer wg.Done()
- if e, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != nil && err != tcpip.ErrWouldBlock {
- t.Errorf("got neigh.entry(%s, '', _, nil, nil) = (%+v, _, %s), want (_, _, nil) or (_, _, %s)", entry.Addr, e, err, tcpip.ErrWouldBlock)
+ switch e, _, err := linkRes.neigh.entry(entry.Addr, "", nil); err.(type) {
+ case nil, *tcpip.ErrWouldBlock:
+ default:
+ t.Errorf("got linkRes.neigh.entry(%s, '', nil) = (%+v, _, %s), want (_, _, nil) or (_, _, %s)", entry.Addr, e, err, &tcpip.ErrWouldBlock{})
}
}(entry)
}
@@ -1379,10 +1350,10 @@ func TestNeighborCacheConcurrent(t *testing.T) {
// The order of entries reported by entries() is nondeterministic, so entries
// have to be sorted before comparison.
var wantUnsortedEntries []NeighborEntry
- for i := store.size() - neighborCacheSize; i < store.size(); i++ {
- entry, ok := store.entry(i)
+ for i := linkRes.entries.size() - neighborCacheSize; i < linkRes.entries.size(); i++ {
+ entry, ok := linkRes.entries.entry(i)
if !ok {
- t.Errorf("store.entry(%d) not found", i)
+ t.Errorf("linkRes.entries.entry(%d) not found", i)
}
wantEntry := NeighborEntry{
Addr: entry.Addr,
@@ -1392,8 +1363,8 @@ func TestNeighborCacheConcurrent(t *testing.T) {
wantUnsortedEntries = append(wantUnsortedEntries, wantEntry)
}
- if diff := cmp.Diff(neigh.entries(), wantUnsortedEntries, entryDiffOptsWithSort()...); diff != "" {
- t.Errorf("neighbor entries mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantUnsortedEntries, linkRes.neigh.entries(), entryDiffOptsWithSort()...); diff != "" {
+ t.Errorf("neighbor entries mismatch (-want, +got):\n%s", diff)
}
}
@@ -1402,41 +1373,34 @@ func TestNeighborCacheReplace(t *testing.T) {
nudDisp := testNUDDispatcher{}
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, config, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- }
+ linkRes := newTestNeighborResolver(&nudDisp, config, clock)
// Add an entry
- entry, ok := store.entry(0)
+ entry, ok := linkRes.entries.entry(0)
if !ok {
- t.Fatal("store.entry(0) not found")
+ t.Fatal("linkRes.entries.entry(0) not found")
}
- _, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ _, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{LinkAddress: entry.LinkAddr, Success: true}, r); diff != "" {
t.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- t.Fatalf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Fatalf("got linkRes.neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
clock.Advance(typicalLatency)
select {
case <-ch:
default:
- t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ t.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
// Verify the entry exists
{
- e, _, err := neigh.entry(entry.Addr, "", linkRes, nil)
+ e, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
if err != nil {
- t.Errorf("unexpected error from neigh.entry(%s, '', _, _, nil): %s", entry.Addr, err)
+ t.Errorf("unexpected error from linkRes.neigh.entry(%s, '', _, _, nil): %s", entry.Addr, err)
}
if t.Failed() {
t.FailNow()
@@ -1446,22 +1410,22 @@ func TestNeighborCacheReplace(t *testing.T) {
LinkAddr: entry.LinkAddr,
State: Reachable,
}
- if diff := cmp.Diff(e, want, entryDiffOpts()...); diff != "" {
- t.Errorf("neigh.entry(%s, '', _, _, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
+ if diff := cmp.Diff(want, e, entryDiffOpts()...); diff != "" {
+ t.Errorf("linkRes.neigh.entry(%s, '', _, _, nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
}
}
// Notify of a link address change
var updatedLinkAddr tcpip.LinkAddress
{
- entry, ok := store.entry(1)
+ entry, ok := linkRes.entries.entry(1)
if !ok {
- t.Fatal("store.entry(1) not found")
+ t.Fatal("linkRes.entries.entry(1) not found")
}
updatedLinkAddr = entry.LinkAddr
}
- store.set(0, updatedLinkAddr)
- neigh.HandleConfirmation(entry.Addr, updatedLinkAddr, ReachabilityConfirmationFlags{
+ linkRes.entries.set(0, updatedLinkAddr)
+ linkRes.neigh.handleConfirmation(entry.Addr, updatedLinkAddr, ReachabilityConfirmationFlags{
Solicited: false,
Override: true,
IsRouter: false,
@@ -1471,35 +1435,35 @@ func TestNeighborCacheReplace(t *testing.T) {
//
// Verify the entry's new link address and the new state.
{
- e, _, err := neigh.entry(entry.Addr, "", linkRes, nil)
+ e, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
if err != nil {
- t.Fatalf("neigh.entry(%s, '', _, nil, nil): %s", entry.Addr, err)
+ t.Fatalf("linkRes.neigh.entry(%s, '', nil): %s", entry.Addr, err)
}
want := NeighborEntry{
Addr: entry.Addr,
LinkAddr: updatedLinkAddr,
State: Delay,
}
- if diff := cmp.Diff(e, want, entryDiffOpts()...); diff != "" {
- t.Errorf("neigh.entry(%s, '', _, nil, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
+ if diff := cmp.Diff(want, e, entryDiffOpts()...); diff != "" {
+ t.Errorf("linkRes.neigh.entry(%s, '', nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
}
clock.Advance(config.DelayFirstProbeTime + typicalLatency)
}
// Verify that the neighbor is now reachable.
{
- e, _, err := neigh.entry(entry.Addr, "", linkRes, nil)
+ e, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
clock.Advance(typicalLatency)
if err != nil {
- t.Errorf("unexpected error from neigh.entry(%s, '', _, nil, nil): %s", entry.Addr, err)
+ t.Errorf("unexpected error from linkRes.neigh.entry(%s, '', nil): %s", entry.Addr, err)
}
want := NeighborEntry{
Addr: entry.Addr,
LinkAddr: updatedLinkAddr,
State: Reachable,
}
- if diff := cmp.Diff(e, want, entryDiffOpts()...); diff != "" {
- t.Errorf("neigh.entry(%s, '', _, nil, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
+ if diff := cmp.Diff(want, e, entryDiffOpts()...); diff != "" {
+ t.Errorf("linkRes.neigh.entry(%s, '', nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
}
}
}
@@ -1509,54 +1473,47 @@ func TestNeighborCacheResolutionFailed(t *testing.T) {
nudDisp := testNUDDispatcher{}
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(&nudDisp, config, clock)
- store := newTestEntryStore()
+ linkRes := newTestNeighborResolver(&nudDisp, config, clock)
var requestCount uint32
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- onLinkAddressRequest: func() {
- atomic.AddUint32(&requestCount, 1)
- },
+ linkRes.onLinkAddressRequest = func() {
+ atomic.AddUint32(&requestCount, 1)
}
- entry, ok := store.entry(0)
+ entry, ok := linkRes.entries.entry(0)
if !ok {
- t.Fatal("store.entry(0) not found")
+ t.Fatal("linkRes.entries.entry(0) not found")
}
// First, sanity check that resolution is working
{
- _, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ _, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{LinkAddress: entry.LinkAddr, Success: true}, r); diff != "" {
t.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- t.Fatalf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Fatalf("got linkRes.neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
clock.Advance(typicalLatency)
select {
case <-ch:
default:
- t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ t.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
}
- got, _, err := neigh.entry(entry.Addr, "", linkRes, nil)
+ got, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
if err != nil {
- t.Fatalf("unexpected error from neigh.entry(%s, '', _, nil, nil): %s", entry.Addr, err)
+ t.Fatalf("unexpected error from linkRes.neigh.entry(%s, '', nil): %s", entry.Addr, err)
}
want := NeighborEntry{
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Reachable,
}
- if diff := cmp.Diff(got, want, entryDiffOpts()...); diff != "" {
- t.Errorf("neigh.entry(%s, '', _, nil, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
+ if diff := cmp.Diff(want, got, entryDiffOpts()...); diff != "" {
+ t.Errorf("linkRes.neigh.entry(%s, '', nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
}
// Verify address resolution fails for an unknown address.
@@ -1564,24 +1521,24 @@ func TestNeighborCacheResolutionFailed(t *testing.T) {
entry.Addr += "2"
{
- _, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ _, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{Success: false}, r); diff != "" {
t.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- t.Fatalf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Fatalf("got linkRes.neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
waitFor := config.DelayFirstProbeTime + typicalLatency*time.Duration(config.MaxMulticastProbes)
clock.Advance(waitFor)
select {
case <-ch:
default:
- t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ t.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
}
- maxAttempts := neigh.config().MaxUnicastProbes
+ maxAttempts := linkRes.neigh.config().MaxUnicastProbes
if got, want := atomic.LoadUint32(&requestCount)-before, maxAttempts; got != want {
t.Errorf("got link address request count = %d, want = %d", got, want)
}
@@ -1595,27 +1552,22 @@ func TestNeighborCacheResolutionTimeout(t *testing.T) {
config.RetransmitTimer = time.Millisecond // small enough to cause timeout
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(nil, config, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: time.Minute, // large enough to cause timeout
- }
+ linkRes := newTestNeighborResolver(nil, config, clock)
+ // large enough to cause timeout
+ linkRes.delay = time.Minute
- entry, ok := store.entry(0)
+ entry, ok := linkRes.entries.entry(0)
if !ok {
- t.Fatal("store.entry(0) not found")
+ t.Fatal("linkRes.entries.entry(0) not found")
}
- _, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ _, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{Success: false}, r); diff != "" {
t.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- t.Fatalf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Fatalf("got linkRes.neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
waitFor := config.RetransmitTimer * time.Duration(config.MaxMulticastProbes)
clock.Advance(waitFor)
@@ -1623,7 +1575,7 @@ func TestNeighborCacheResolutionTimeout(t *testing.T) {
select {
case <-ch:
default:
- t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ t.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
}
@@ -1632,31 +1584,24 @@ func TestNeighborCacheResolutionTimeout(t *testing.T) {
func TestNeighborCacheRetryResolution(t *testing.T) {
config := DefaultNUDConfigurations()
clock := faketime.NewManualClock()
- neigh := newTestNeighborCache(nil, config, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: typicalLatency,
- // Simulate a faulty link.
- dropReplies: true,
- }
+ linkRes := newTestNeighborResolver(nil, config, clock)
+ // Simulate a faulty link.
+ linkRes.dropReplies = true
- entry, ok := store.entry(0)
+ entry, ok := linkRes.entries.entry(0)
if !ok {
- t.Fatal("store.entry(0) not found")
+ t.Fatal("linkRes.entries.entry(0) not found")
}
// Perform address resolution with a faulty link, which will fail.
{
- _, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ _, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{Success: false}, r); diff != "" {
t.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- t.Fatalf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Fatalf("got linkRes.neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
waitFor := config.RetransmitTimer * time.Duration(config.MaxMulticastProbes)
clock.Advance(waitFor)
@@ -1664,7 +1609,7 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
select {
case <-ch:
default:
- t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ t.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
}
@@ -1676,20 +1621,20 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
State: Failed,
},
}
- if diff := cmp.Diff(neigh.entries(), wantEntries, entryDiffOptsWithSort()...); diff != "" {
+ if diff := cmp.Diff(linkRes.neigh.entries(), wantEntries, entryDiffOptsWithSort()...); diff != "" {
t.Fatalf("neighbor entries mismatch (-got, +want):\n%s", diff)
}
// Retry address resolution with a working link.
linkRes.dropReplies = false
{
- incompleteEntry, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ incompleteEntry, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{LinkAddress: entry.LinkAddr, Success: true}, r); diff != "" {
t.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- t.Fatalf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ t.Fatalf("got linkRes.neigh.entry(%s, '', _) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
if incompleteEntry.State != Incomplete {
t.Fatalf("got entry.State = %s, want = %s", incompleteEntry.State, Incomplete)
@@ -1701,9 +1646,9 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
if !ok {
t.Fatal("expected successful address resolution")
}
- reachableEntry, _, err := neigh.entry(entry.Addr, "", linkRes, nil)
+ reachableEntry, _, err := linkRes.neigh.entry(entry.Addr, "", nil)
if err != nil {
- t.Fatalf("neigh.entry(%s, '', _, _, nil): %v", entry.Addr, err)
+ t.Fatalf("linkRes.neigh.entry(%s, '', _, _, nil): %v", entry.Addr, err)
}
if reachableEntry.Addr != entry.Addr {
t.Fatalf("got entry.Addr = %s, want = %s", reachableEntry.Addr, entry.Addr)
@@ -1715,7 +1660,7 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
t.Fatalf("got entry.State = %s, want = %s", reachableEntry.State.String(), Reachable.String())
}
default:
- t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ t.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
}
}
@@ -1724,42 +1669,36 @@ func BenchmarkCacheClear(b *testing.B) {
b.StopTimer()
config := DefaultNUDConfigurations()
clock := &tcpip.StdClock{}
- neigh := newTestNeighborCache(nil, config, clock)
- store := newTestEntryStore()
- linkRes := &testNeighborResolver{
- clock: clock,
- neigh: neigh,
- entries: store,
- delay: 0,
- }
+ linkRes := newTestNeighborResolver(nil, config, clock)
+ linkRes.delay = 0
// Clear for every possible size of the cache
for cacheSize := 0; cacheSize < neighborCacheSize; cacheSize++ {
// Fill the neighbor cache to capacity.
for i := 0; i < cacheSize; i++ {
- entry, ok := store.entry(i)
+ entry, ok := linkRes.entries.entry(i)
if !ok {
- b.Fatalf("store.entry(%d) not found", i)
+ b.Fatalf("linkRes.entries.entry(%d) not found", i)
}
- _, ch, err := neigh.entry(entry.Addr, "", linkRes, func(r LinkResolutionResult) {
+ _, ch, err := linkRes.neigh.entry(entry.Addr, "", func(r LinkResolutionResult) {
if diff := cmp.Diff(LinkResolutionResult{LinkAddress: entry.LinkAddr, Success: true}, r); diff != "" {
b.Fatalf("got link resolution result mismatch (-want +got):\n%s", diff)
}
})
- if err != tcpip.ErrWouldBlock {
- b.Fatalf("got neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
+ if _, ok := err.(*tcpip.ErrWouldBlock); !ok {
+ b.Fatalf("got linkRes.neigh.entry(%s, '', _, _, nil) = %v, want = %s", entry.Addr, err, &tcpip.ErrWouldBlock{})
}
select {
case <-ch:
default:
- b.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, _, nil)", entry.Addr)
+ b.Fatalf("expected notification from done channel returned by linkRes.neigh.entry(%s, '', _, _, nil)", entry.Addr)
}
}
b.StartTimer()
- neigh.clear()
+ linkRes.neigh.clear()
b.StopTimer()
}
}
diff --git a/pkg/tcpip/stack/neighbor_entry.go b/pkg/tcpip/stack/neighbor_entry.go
index 53ac9bb6e..b05f96d4f 100644
--- a/pkg/tcpip/stack/neighbor_entry.go
+++ b/pkg/tcpip/stack/neighbor_entry.go
@@ -77,11 +77,7 @@ const (
type neighborEntry struct {
neighborEntryEntry
- nic *NIC
-
- // linkRes provides the functionality to send reachability probes, used in
- // Neighbor Unreachability Detection.
- linkRes LinkAddressResolver
+ cache *neighborCache
// nudState points to the Neighbor Unreachability Detection configuration.
nudState *NUDState
@@ -106,10 +102,9 @@ type neighborEntry struct {
// state, Unknown. Transition out of Unknown by calling either
// `handlePacketQueuedLocked` or `handleProbeLocked` on the newly created
// neighborEntry.
-func newNeighborEntry(nic *NIC, remoteAddr tcpip.Address, nudState *NUDState, linkRes LinkAddressResolver) *neighborEntry {
+func newNeighborEntry(cache *neighborCache, remoteAddr tcpip.Address, nudState *NUDState) *neighborEntry {
return &neighborEntry{
- nic: nic,
- linkRes: linkRes,
+ cache: cache,
nudState: nudState,
neigh: NeighborEntry{
Addr: remoteAddr,
@@ -121,18 +116,18 @@ func newNeighborEntry(nic *NIC, remoteAddr tcpip.Address, nudState *NUDState, li
// newStaticNeighborEntry creates a neighbor cache entry starting at the
// Static state. The entry can only transition out of Static by directly
// calling `setStateLocked`.
-func newStaticNeighborEntry(nic *NIC, addr tcpip.Address, linkAddr tcpip.LinkAddress, state *NUDState) *neighborEntry {
+func newStaticNeighborEntry(cache *neighborCache, addr tcpip.Address, linkAddr tcpip.LinkAddress, state *NUDState) *neighborEntry {
entry := NeighborEntry{
Addr: addr,
LinkAddr: linkAddr,
State: Static,
- UpdatedAtNanos: nic.stack.clock.NowNanoseconds(),
+ UpdatedAtNanos: cache.nic.stack.clock.NowNanoseconds(),
}
- if nic.stack.nudDisp != nil {
- nic.stack.nudDisp.OnNeighborAdded(nic.id, entry)
+ if nudDisp := cache.nic.stack.nudDisp; nudDisp != nil {
+ nudDisp.OnNeighborAdded(cache.nic.id, entry)
}
return &neighborEntry{
- nic: nic,
+ cache: cache,
nudState: state,
neigh: entry,
}
@@ -158,7 +153,7 @@ func (e *neighborEntry) notifyCompletionLocked(succeeded bool) {
// is resolved (which ends up obtaining the entry's lock) while holding the
// link resolution queue's lock. Dequeuing packets in a new goroutine avoids
// a lock ordering violation.
- go e.nic.linkResQueue.dequeue(ch, e.neigh.LinkAddr, succeeded)
+ go e.cache.nic.linkResQueue.dequeue(ch, e.neigh.LinkAddr, succeeded)
}
}
@@ -167,8 +162,8 @@ func (e *neighborEntry) notifyCompletionLocked(succeeded bool) {
//
// Precondition: e.mu MUST be locked.
func (e *neighborEntry) dispatchAddEventLocked() {
- if nudDisp := e.nic.stack.nudDisp; nudDisp != nil {
- nudDisp.OnNeighborAdded(e.nic.id, e.neigh)
+ if nudDisp := e.cache.nic.stack.nudDisp; nudDisp != nil {
+ nudDisp.OnNeighborAdded(e.cache.nic.id, e.neigh)
}
}
@@ -177,8 +172,8 @@ func (e *neighborEntry) dispatchAddEventLocked() {
//
// Precondition: e.mu MUST be locked.
func (e *neighborEntry) dispatchChangeEventLocked() {
- if nudDisp := e.nic.stack.nudDisp; nudDisp != nil {
- nudDisp.OnNeighborChanged(e.nic.id, e.neigh)
+ if nudDisp := e.cache.nic.stack.nudDisp; nudDisp != nil {
+ nudDisp.OnNeighborChanged(e.cache.nic.id, e.neigh)
}
}
@@ -187,8 +182,8 @@ func (e *neighborEntry) dispatchChangeEventLocked() {
//
// Precondition: e.mu MUST be locked.
func (e *neighborEntry) dispatchRemoveEventLocked() {
- if nudDisp := e.nic.stack.nudDisp; nudDisp != nil {
- nudDisp.OnNeighborRemoved(e.nic.id, e.neigh)
+ if nudDisp := e.cache.nic.stack.nudDisp; nudDisp != nil {
+ nudDisp.OnNeighborRemoved(e.cache.nic.id, e.neigh)
}
}
@@ -206,7 +201,7 @@ func (e *neighborEntry) cancelJobLocked() {
//
// Precondition: e.mu MUST be locked.
func (e *neighborEntry) removeLocked() {
- e.neigh.UpdatedAtNanos = e.nic.stack.clock.NowNanoseconds()
+ e.neigh.UpdatedAtNanos = e.cache.nic.stack.clock.NowNanoseconds()
e.dispatchRemoveEventLocked()
e.cancelJobLocked()
e.notifyCompletionLocked(false /* succeeded */)
@@ -222,7 +217,7 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
prev := e.neigh.State
e.neigh.State = next
- e.neigh.UpdatedAtNanos = e.nic.stack.clock.NowNanoseconds()
+ e.neigh.UpdatedAtNanos = e.cache.nic.stack.clock.NowNanoseconds()
config := e.nudState.Config()
switch next {
@@ -230,14 +225,14 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
panic(fmt.Sprintf("should never transition to Incomplete with setStateLocked; neigh = %#v, prev state = %s", e.neigh, prev))
case Reachable:
- e.job = e.nic.stack.newJob(&e.mu, func() {
+ e.job = e.cache.nic.stack.newJob(&e.mu, func() {
e.setStateLocked(Stale)
e.dispatchChangeEventLocked()
})
e.job.Schedule(e.nudState.ReachableTime())
case Delay:
- e.job = e.nic.stack.newJob(&e.mu, func() {
+ e.job = e.cache.nic.stack.newJob(&e.mu, func() {
e.setStateLocked(Probe)
e.dispatchChangeEventLocked()
})
@@ -254,14 +249,14 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
return
}
- if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, "" /* localAddr */, e.neigh.LinkAddr, e.nic); err != nil {
+ if err := e.cache.linkRes.LinkAddressRequest(e.neigh.Addr, "" /* localAddr */, e.neigh.LinkAddr); err != nil {
e.dispatchRemoveEventLocked()
e.setStateLocked(Failed)
return
}
retryCounter++
- e.job = e.nic.stack.newJob(&e.mu, sendUnicastProbe)
+ e.job = e.cache.nic.stack.newJob(&e.mu, sendUnicastProbe)
e.job.Schedule(config.RetransmitTimer)
}
@@ -269,7 +264,7 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
// for finishing the state transition. This is necessary to avoid
// deadlock where sending and processing probes are done synchronously,
// such as loopback and integration tests.
- e.job = e.nic.stack.newJob(&e.mu, sendUnicastProbe)
+ e.job = e.cache.nic.stack.newJob(&e.mu, sendUnicastProbe)
e.job.Schedule(immediateDuration)
case Failed:
@@ -292,12 +287,12 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) {
switch e.neigh.State {
case Failed:
- e.nic.stats.Neighbor.FailedEntryLookups.Increment()
+ e.cache.nic.stats.Neighbor.FailedEntryLookups.Increment()
fallthrough
case Unknown:
e.neigh.State = Incomplete
- e.neigh.UpdatedAtNanos = e.nic.stack.clock.NowNanoseconds()
+ e.neigh.UpdatedAtNanos = e.cache.nic.stack.clock.NowNanoseconds()
e.dispatchAddEventLocked()
@@ -340,7 +335,7 @@ func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) {
// address SHOULD be placed in the IP Source Address of the outgoing
// solicitation.
//
- if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, localAddr, "", e.nic); err != nil {
+ if err := e.cache.linkRes.LinkAddressRequest(e.neigh.Addr, localAddr, ""); err != nil {
// There is no need to log the error here; the NUD implementation may
// assume a working link. A valid link should be the responsibility of
// the NIC/stack.LinkEndpoint.
@@ -350,7 +345,7 @@ func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) {
}
retryCounter++
- e.job = e.nic.stack.newJob(&e.mu, sendMulticastProbe)
+ e.job = e.cache.nic.stack.newJob(&e.mu, sendMulticastProbe)
e.job.Schedule(config.RetransmitTimer)
}
@@ -358,7 +353,7 @@ func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) {
// for finishing the state transition. This is necessary to avoid
// deadlock where sending and processing probes are done synchronously,
// such as loopback and integration tests.
- e.job = e.nic.stack.newJob(&e.mu, sendMulticastProbe)
+ e.job = e.cache.nic.stack.newJob(&e.mu, sendMulticastProbe)
e.job.Schedule(immediateDuration)
case Stale:
@@ -504,7 +499,7 @@ func (e *neighborEntry) handleConfirmationLocked(linkAddr tcpip.LinkAddress, fla
//
// TODO(gvisor.dev/issue/4085): Remove the special casing we do for IPv6
// here.
- ep, ok := e.nic.networkEndpoints[header.IPv6ProtocolNumber]
+ ep, ok := e.cache.nic.networkEndpoints[header.IPv6ProtocolNumber]
if !ok {
panic(fmt.Sprintf("have a neighbor entry for an IPv6 router but no IPv6 network endpoint"))
}
diff --git a/pkg/tcpip/stack/neighbor_entry_test.go b/pkg/tcpip/stack/neighbor_entry_test.go
index ec34ffa5a..57cfbdb8b 100644
--- a/pkg/tcpip/stack/neighbor_entry_test.go
+++ b/pkg/tcpip/stack/neighbor_entry_test.go
@@ -193,7 +193,7 @@ func (p entryTestProbeInfo) String() string {
// LinkAddressRequest sends a request for the LinkAddress of addr. Broadcasts
// to the local network if linkAddr is the zero value.
-func (r *entryTestLinkResolver) LinkAddressRequest(targetAddr, localAddr tcpip.Address, linkAddr tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
+func (r *entryTestLinkResolver) LinkAddressRequest(targetAddr, localAddr tcpip.Address, linkAddr tcpip.LinkAddress) tcpip.Error {
p := entryTestProbeInfo{
RemoteAddress: targetAddr,
RemoteLinkAddress: linkAddr,
@@ -230,22 +230,30 @@ func entryTestSetup(c NUDConfigurations) (*neighborEntry, *testNUDDispatcher, *e
},
stats: makeNICStats(),
}
+ netEP := (&testIPv6Protocol{}).NewEndpoint(&nic, nil)
nic.networkEndpoints = map[tcpip.NetworkProtocolNumber]NetworkEndpoint{
- header.IPv6ProtocolNumber: (&testIPv6Protocol{}).NewEndpoint(&nic, nil, nil, nil),
+ header.IPv6ProtocolNumber: netEP,
}
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
nudState := NewNUDState(c, rng)
- linkRes := entryTestLinkResolver{}
- entry := newNeighborEntry(&nic, entryTestAddr1 /* remoteAddr */, nudState, &linkRes)
-
+ var linkRes entryTestLinkResolver
// Stub out the neighbor cache to verify deletion from the cache.
- nic.neigh = &neighborCache{
- nic: &nic,
- state: nudState,
- cache: make(map[tcpip.Address]*neighborEntry, neighborCacheSize),
+ neigh := &neighborCache{
+ nic: &nic,
+ state: nudState,
+ linkRes: &linkRes,
+ cache: make(map[tcpip.Address]*neighborEntry, neighborCacheSize),
+ }
+ l := linkResolver{
+ resolver: &linkRes,
+ neighborTable: neigh,
+ }
+ entry := newNeighborEntry(neigh, entryTestAddr1 /* remoteAddr */, nudState)
+ neigh.cache[entryTestAddr1] = entry
+ nic.linkAddrResolvers = map[tcpip.NetworkProtocolNumber]linkResolver{
+ header.IPv6ProtocolNumber: l,
}
- nic.neigh.cache[entryTestAddr1] = entry
return entry, &disp, &linkRes, clock
}
@@ -266,16 +274,16 @@ func TestEntryInitiallyUnknown(t *testing.T) {
// No probes should have been sent.
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, []entryTestProbeInfo(nil))
+ diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
// No events should have been dispatched.
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, []testEntryEventInfo(nil)); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.events); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -299,16 +307,16 @@ func TestEntryUnknownToUnknownWhenConfirmationWithUnknownAddress(t *testing.T) {
// No probes should have been sent.
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, []entryTestProbeInfo(nil))
+ diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
// No events should have been dispatched.
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, []testEntryEventInfo(nil)); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.events); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -333,10 +341,10 @@ func TestEntryUnknownToIncomplete(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
wantEvents := []testEntryEventInfo{
@@ -352,10 +360,10 @@ func TestEntryUnknownToIncomplete(t *testing.T) {
}
{
nudDisp.mu.Lock()
- diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...)
+ diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...)
nudDisp.mu.Unlock()
if diff != "" {
- t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
}
}
@@ -374,10 +382,10 @@ func TestEntryUnknownToStale(t *testing.T) {
// No probes should have been sent.
runImmediatelyScheduledJobs(clock)
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, []entryTestProbeInfo(nil))
+ diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
wantEvents := []testEntryEventInfo{
@@ -392,8 +400,8 @@ func TestEntryUnknownToStale(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -427,11 +435,11 @@ func TestEntryIncompleteToIncompleteDoesNotChangeUpdatedAt(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -453,10 +461,10 @@ func TestEntryIncompleteToIncompleteDoesNotChangeUpdatedAt(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -483,8 +491,8 @@ func TestEntryIncompleteToIncompleteDoesNotChangeUpdatedAt(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
@@ -515,10 +523,10 @@ func TestEntryIncompleteToReachable(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -553,8 +561,8 @@ func TestEntryIncompleteToReachable(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -579,10 +587,10 @@ func TestEntryIncompleteToReachableWithRouterFlag(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -620,8 +628,8 @@ func TestEntryIncompleteToReachableWithRouterFlag(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -646,10 +654,10 @@ func TestEntryIncompleteToStaleWhenUnsolicitedConfirmation(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -684,8 +692,8 @@ func TestEntryIncompleteToStaleWhenUnsolicitedConfirmation(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -710,10 +718,10 @@ func TestEntryIncompleteToStaleWhenProbe(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -744,8 +752,8 @@ func TestEntryIncompleteToStaleWhenProbe(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -785,10 +793,10 @@ func TestEntryIncompleteToFailed(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
wantEvents := []testEntryEventInfo{
@@ -812,8 +820,8 @@ func TestEntryIncompleteToFailed(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
@@ -835,7 +843,7 @@ func TestEntryStaysReachableWhenConfirmationWithRouterFlag(t *testing.T) {
c := DefaultNUDConfigurations()
e, nudDisp, linkRes, clock := entryTestSetup(c)
- ipv6EP := e.nic.networkEndpoints[header.IPv6ProtocolNumber].(*testIPv6Endpoint)
+ ipv6EP := e.cache.nic.networkEndpoints[header.IPv6ProtocolNumber].(*testIPv6Endpoint)
e.mu.Lock()
e.handlePacketQueuedLocked(entryTestAddr2)
@@ -850,10 +858,10 @@ func TestEntryStaysReachableWhenConfirmationWithRouterFlag(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -903,8 +911,8 @@ func TestEntryStaysReachableWhenConfirmationWithRouterFlag(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
@@ -932,10 +940,10 @@ func TestEntryStaysReachableWhenProbeWithSameAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -977,8 +985,8 @@ func TestEntryStaysReachableWhenProbeWithSameAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1005,10 +1013,10 @@ func TestEntryReachableToStaleWhenTimeout(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1054,8 +1062,8 @@ func TestEntryReachableToStaleWhenTimeout(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
@@ -1083,10 +1091,10 @@ func TestEntryReachableToStaleWhenProbeWithDifferentAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1134,8 +1142,8 @@ func TestEntryReachableToStaleWhenProbeWithDifferentAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1157,10 +1165,10 @@ func TestEntryReachableToStaleWhenConfirmationWithDifferentAddress(t *testing.T)
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1212,8 +1220,8 @@ func TestEntryReachableToStaleWhenConfirmationWithDifferentAddress(t *testing.T)
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1235,10 +1243,10 @@ func TestEntryReachableToStaleWhenConfirmationWithDifferentAddressAndOverride(t
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1290,8 +1298,8 @@ func TestEntryReachableToStaleWhenConfirmationWithDifferentAddressAndOverride(t
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1313,10 +1321,10 @@ func TestEntryStaysStaleWhenProbeWithSameAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1358,8 +1366,8 @@ func TestEntryStaysStaleWhenProbeWithSameAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1381,10 +1389,10 @@ func TestEntryStaleToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1439,8 +1447,8 @@ func TestEntryStaleToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1462,10 +1470,10 @@ func TestEntryStaleToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1520,8 +1528,8 @@ func TestEntryStaleToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1543,10 +1551,10 @@ func TestEntryStaleToStaleWhenOverrideConfirmation(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1601,8 +1609,8 @@ func TestEntryStaleToStaleWhenOverrideConfirmation(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1624,10 +1632,10 @@ func TestEntryStaleToStaleWhenProbeUpdateAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1678,8 +1686,8 @@ func TestEntryStaleToStaleWhenProbeUpdateAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1701,10 +1709,10 @@ func TestEntryStaleToDelay(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1752,8 +1760,8 @@ func TestEntryStaleToDelay(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1780,10 +1788,10 @@ func TestEntryDelayToReachableWhenUpperLevelConfirmation(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1851,8 +1859,8 @@ func TestEntryDelayToReachableWhenUpperLevelConfirmation(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1880,10 +1888,10 @@ func TestEntryDelayToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -1958,8 +1966,8 @@ func TestEntryDelayToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -1987,10 +1995,10 @@ func TestEntryDelayToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -2065,8 +2073,8 @@ func TestEntryDelayToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -2088,10 +2096,10 @@ func TestEntryStaysDelayWhenOverrideConfirmationWithSameAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -2147,8 +2155,8 @@ func TestEntryStaysDelayWhenOverrideConfirmationWithSameAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -2170,10 +2178,10 @@ func TestEntryDelayToStaleWhenProbeWithDifferentAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -2231,8 +2239,8 @@ func TestEntryDelayToStaleWhenProbeWithDifferentAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -2254,10 +2262,10 @@ func TestEntryDelayToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -2319,8 +2327,8 @@ func TestEntryDelayToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -2343,11 +2351,11 @@ func TestEntryDelayToProbe(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2372,10 +2380,10 @@ func TestEntryDelayToProbe(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2418,8 +2426,8 @@ func TestEntryDelayToProbe(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
@@ -2448,11 +2456,11 @@ func TestEntryProbeToStaleWhenProbeWithDifferentAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2474,10 +2482,10 @@ func TestEntryProbeToStaleWhenProbeWithDifferentAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2539,8 +2547,8 @@ func TestEntryProbeToStaleWhenProbeWithDifferentAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -2563,11 +2571,11 @@ func TestEntryProbeToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2589,10 +2597,10 @@ func TestEntryProbeToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2658,8 +2666,8 @@ func TestEntryProbeToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -2682,11 +2690,11 @@ func TestEntryStaysProbeWhenOverrideConfirmationWithSameAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2709,10 +2717,10 @@ func TestEntryStaysProbeWhenOverrideConfirmationWithSameAddress(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2772,8 +2780,8 @@ func TestEntryStaysProbeWhenOverrideConfirmationWithSameAddress(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -2806,10 +2814,10 @@ func TestEntryUnknownToStaleToProbeToReachable(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -2878,8 +2886,8 @@ func TestEntryUnknownToStaleToProbeToReachable(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -2907,11 +2915,11 @@ func TestEntryProbeToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -2933,10 +2941,10 @@ func TestEntryProbeToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -3015,8 +3023,8 @@ func TestEntryProbeToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -3044,11 +3052,11 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithSameAddress(t *testin
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -3070,10 +3078,10 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithSameAddress(t *testin
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -3149,8 +3157,8 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithSameAddress(t *testin
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -3178,11 +3186,11 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -3204,10 +3212,10 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -3283,8 +3291,8 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -3309,11 +3317,11 @@ func TestEntryProbeToFailed(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
}
@@ -3336,11 +3344,11 @@ func TestEntryProbeToFailed(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.probes = nil
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probe #%d mismatch (-got, +want):\n%s", i+1, diff)
+ t.Fatalf("link address resolver probe #%d mismatch (-want, +got):\n%s", i+1, diff)
}
e.mu.Lock()
@@ -3406,8 +3414,8 @@ func TestEntryProbeToFailed(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
@@ -3449,10 +3457,10 @@ func TestEntryFailedToIncomplete(t *testing.T) {
},
}
linkRes.mu.Lock()
- diff := cmp.Diff(linkRes.probes, wantProbes)
+ diff := cmp.Diff(wantProbes, linkRes.probes)
linkRes.mu.Unlock()
if diff != "" {
- t.Fatalf("link address resolver probes mismatch (-got, +want):\n%s", diff)
+ t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff)
}
e.mu.Lock()
@@ -3498,8 +3506,8 @@ func TestEntryFailedToIncomplete(t *testing.T) {
},
}
nudDisp.mu.Lock()
- if diff := cmp.Diff(nudDisp.events, wantEvents, eventDiffOpts()...); diff != "" {
- t.Errorf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
+ if diff := cmp.Diff(wantEvents, nudDisp.events, eventDiffOpts()...); diff != "" {
+ t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff)
}
nudDisp.mu.Unlock()
}
diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go
index 1bbfe6213..41a489047 100644
--- a/pkg/tcpip/stack/nic.go
+++ b/pkg/tcpip/stack/nic.go
@@ -16,7 +16,6 @@ package stack
import (
"fmt"
- "math/rand"
"reflect"
"sync/atomic"
@@ -25,8 +24,37 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/header"
)
+type neighborTable interface {
+ neighbors() ([]NeighborEntry, tcpip.Error)
+ addStaticEntry(tcpip.Address, tcpip.LinkAddress)
+ get(addr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (tcpip.LinkAddress, <-chan struct{}, tcpip.Error)
+ remove(tcpip.Address) tcpip.Error
+ removeAll() tcpip.Error
+
+ handleProbe(tcpip.Address, tcpip.LinkAddress)
+ handleConfirmation(tcpip.Address, tcpip.LinkAddress, ReachabilityConfirmationFlags)
+ handleUpperLevelConfirmation(tcpip.Address)
+
+ nudConfig() (NUDConfigurations, tcpip.Error)
+ setNUDConfig(NUDConfigurations) tcpip.Error
+}
+
var _ NetworkInterface = (*NIC)(nil)
+type linkResolver struct {
+ resolver LinkAddressResolver
+
+ neighborTable neighborTable
+}
+
+func (l *linkResolver) getNeighborLinkAddress(addr, localAddr tcpip.Address, onResolve func(LinkResolutionResult)) (tcpip.LinkAddress, <-chan struct{}, tcpip.Error) {
+ return l.neighborTable.get(addr, localAddr, onResolve)
+}
+
+func (l *linkResolver) confirmReachable(addr tcpip.Address) {
+ l.neighborTable.handleUpperLevelConfirmation(addr)
+}
+
// NIC represents a "network interface card" to which the networking stack is
// attached.
type NIC struct {
@@ -38,11 +66,11 @@ type NIC struct {
context NICContext
stats NICStats
- neigh *neighborCache
// The network endpoints themselves may be modified by calling the interface's
// methods, but the map reference and entries must be constant.
- networkEndpoints map[tcpip.NetworkProtocolNumber]NetworkEndpoint
+ networkEndpoints map[tcpip.NetworkProtocolNumber]NetworkEndpoint
+ linkAddrResolvers map[tcpip.NetworkProtocolNumber]linkResolver
// enabled is set to 1 when the NIC is enabled and 0 when it is disabled.
//
@@ -53,8 +81,6 @@ type NIC struct {
// complete.
linkResQueue packetsPendingLinkResolution
- linkAddrCache *linkAddrCache
-
mu struct {
sync.RWMutex
spoofing bool
@@ -133,35 +159,18 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICC
nic := &NIC{
LinkEndpoint: ep,
- stack: stack,
- id: id,
- name: name,
- context: ctx,
- stats: makeNICStats(),
- networkEndpoints: make(map[tcpip.NetworkProtocolNumber]NetworkEndpoint),
+ stack: stack,
+ id: id,
+ name: name,
+ context: ctx,
+ stats: makeNICStats(),
+ networkEndpoints: make(map[tcpip.NetworkProtocolNumber]NetworkEndpoint),
+ linkAddrResolvers: make(map[tcpip.NetworkProtocolNumber]linkResolver),
}
nic.linkResQueue.init(nic)
- nic.linkAddrCache = newLinkAddrCache(nic, ageLimit, resolutionTimeout, resolutionAttempts)
nic.mu.packetEPs = make(map[tcpip.NetworkProtocolNumber]*packetEndpointList)
- // Check for Neighbor Unreachability Detection support.
- var nud NUDHandler
- if ep.Capabilities()&CapabilityResolutionRequired != 0 && len(stack.linkAddrResolvers) != 0 && stack.useNeighborCache {
- rng := rand.New(rand.NewSource(stack.clock.NowNanoseconds()))
- nic.neigh = &neighborCache{
- nic: nic,
- state: NewNUDState(stack.nudConfigs, rng),
- cache: make(map[tcpip.Address]*neighborEntry, neighborCacheSize),
- }
-
- // An interface value that holds a nil pointer but non-nil type is not the
- // same as the nil interface. Because of this, nud must only be assignd if
- // nic.neigh is non-nil since a nil reference to a neighborCache is not
- // valid.
- //
- // See https://golang.org/doc/faq#nil_error for more information.
- nud = nic.neigh
- }
+ resolutionRequired := ep.Capabilities()&CapabilityResolutionRequired != 0
// Register supported packet and network endpoint protocols.
for _, netProto := range header.Ethertypes {
@@ -170,7 +179,32 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICC
for _, netProto := range stack.networkProtocols {
netNum := netProto.Number()
nic.mu.packetEPs[netNum] = new(packetEndpointList)
- nic.networkEndpoints[netNum] = netProto.NewEndpoint(nic, nic.linkAddrCache, nud, nic)
+
+ netEP := netProto.NewEndpoint(nic, nic)
+ nic.networkEndpoints[netNum] = netEP
+
+ if resolutionRequired {
+ if r, ok := netEP.(LinkAddressResolver); ok {
+ l := linkResolver{
+ resolver: r,
+ }
+
+ if stack.useNeighborCache {
+ l.neighborTable = &neighborCache{
+ nic: nic,
+ state: NewNUDState(stack.nudConfigs, stack.randomGenerator),
+ linkRes: r,
+
+ cache: make(map[tcpip.Address]*neighborEntry, neighborCacheSize),
+ }
+ } else {
+ cache := new(linkAddrCache)
+ cache.init(nic, ageLimit, resolutionTimeout, resolutionAttempts, r)
+ l.neighborTable = cache
+ }
+ nic.linkAddrResolvers[r.LinkAddressProtocol()] = l
+ }
+ }
}
nic.LinkEndpoint.Attach(nic)
@@ -223,16 +257,19 @@ func (n *NIC) disableLocked() {
for _, ep := range n.networkEndpoints {
ep.Disable()
- }
- // Clear the neighbour table (including static entries) as we cannot guarantee
- // that the current neighbour table will be valid when the NIC is enabled
- // again.
- //
- // This matches linux's behaviour at the time of writing:
- // https://github.com/torvalds/linux/blob/71c061d2443814de15e177489d5cc00a4a253ef3/net/core/neighbour.c#L371
- if err := n.clearNeighbors(); err != nil && err != tcpip.ErrNotSupported {
- panic(fmt.Sprintf("n.clearNeighbors(): %s", err))
+ // Clear the neighbour table (including static entries) as we cannot
+ // guarantee that the current neighbour table will be valid when the NIC is
+ // enabled again.
+ //
+ // This matches linux's behaviour at the time of writing:
+ // https://github.com/torvalds/linux/blob/71c061d2443814de15e177489d5cc00a4a253ef3/net/core/neighbour.c#L371
+ netProto := ep.NetworkProtocolNumber()
+ switch err := n.clearNeighbors(netProto); err.(type) {
+ case nil, *tcpip.ErrNotSupported:
+ default:
+ panic(fmt.Sprintf("n.clearNeighbors(%d): %s", netProto, err))
+ }
}
if !n.setEnabled(false) {
@@ -246,7 +283,7 @@ func (n *NIC) disableLocked() {
// address (ff02::1), start DAD for permanent addresses, and start soliciting
// routers if the stack is not operating as a router. If the stack is also
// configured to auto-generate a link-local address, one will be generated.
-func (n *NIC) enable() *tcpip.Error {
+func (n *NIC) enable() tcpip.Error {
n.mu.Lock()
defer n.mu.Unlock()
@@ -266,7 +303,7 @@ func (n *NIC) enable() *tcpip.Error {
// remove detaches NIC from the link endpoint and releases network endpoint
// resources. This guarantees no packets between this NIC and the network
// stack.
-func (n *NIC) remove() *tcpip.Error {
+func (n *NIC) remove() tcpip.Error {
n.mu.Lock()
defer n.mu.Unlock()
@@ -302,40 +339,63 @@ func (n *NIC) IsLoopback() bool {
}
// WritePacket implements NetworkLinkEndpoint.
-func (n *NIC) WritePacket(r *Route, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) *tcpip.Error {
+func (n *NIC) WritePacket(r *Route, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) tcpip.Error {
_, err := n.enqueuePacketBuffer(r, gso, protocol, pkt)
return err
}
-func (n *NIC) enqueuePacketBuffer(r *Route, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt pendingPacketBuffer) (int, *tcpip.Error) {
- // As per relevant RFCs, we should queue packets while we wait for link
- // resolution to complete.
- //
- // RFC 1122 section 2.3.2.2 (for IPv4):
- // The link layer SHOULD save (rather than discard) at least
- // one (the latest) packet of each set of packets destined to
- // the same unresolved IP address, and transmit the saved
- // packet when the address has been resolved.
- //
- // RFC 4861 section 7.2.2 (for IPv6):
- // While waiting for address resolution to complete, the sender MUST, for
- // each neighbor, retain a small queue of packets waiting for address
- // resolution to complete. The queue MUST hold at least one packet, and MAY
- // contain more. However, the number of queued packets per neighbor SHOULD
- // be limited to some small value. When a queue overflows, the new arrival
- // SHOULD replace the oldest entry. Once address resolution completes, the
- // node transmits any queued packets.
- return n.linkResQueue.enqueue(r, gso, protocol, pkt)
+
+func (n *NIC) writePacketBuffer(r RouteInfo, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt pendingPacketBuffer) (int, tcpip.Error) {
+ switch pkt := pkt.(type) {
+ case *PacketBuffer:
+ if err := n.writePacket(r, gso, protocol, pkt); err != nil {
+ return 0, err
+ }
+ return 1, nil
+ case *PacketBufferList:
+ return n.writePackets(r, gso, protocol, *pkt)
+ default:
+ panic(fmt.Sprintf("unrecognized pending packet buffer type = %T", pkt))
+ }
+}
+
+func (n *NIC) enqueuePacketBuffer(r *Route, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt pendingPacketBuffer) (int, tcpip.Error) {
+ routeInfo, _, err := r.resolvedFields(nil)
+ switch err.(type) {
+ case nil:
+ return n.writePacketBuffer(routeInfo, gso, protocol, pkt)
+ case *tcpip.ErrWouldBlock:
+ // As per relevant RFCs, we should queue packets while we wait for link
+ // resolution to complete.
+ //
+ // RFC 1122 section 2.3.2.2 (for IPv4):
+ // The link layer SHOULD save (rather than discard) at least
+ // one (the latest) packet of each set of packets destined to
+ // the same unresolved IP address, and transmit the saved
+ // packet when the address has been resolved.
+ //
+ // RFC 4861 section 7.2.2 (for IPv6):
+ // While waiting for address resolution to complete, the sender MUST, for
+ // each neighbor, retain a small queue of packets waiting for address
+ // resolution to complete. The queue MUST hold at least one packet, and
+ // MAY contain more. However, the number of queued packets per neighbor
+ // SHOULD be limited to some small value. When a queue overflows, the new
+ // arrival SHOULD replace the oldest entry. Once address resolution
+ // completes, the node transmits any queued packets.
+ return n.linkResQueue.enqueue(r, gso, protocol, pkt)
+ default:
+ return 0, err
+ }
}
// WritePacketToRemote implements NetworkInterface.
-func (n *NIC) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) *tcpip.Error {
+func (n *NIC) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) tcpip.Error {
var r RouteInfo
r.NetProto = protocol
r.RemoteLinkAddress = remoteLinkAddr
return n.writePacket(r, gso, protocol, pkt)
}
-func (n *NIC) writePacket(r RouteInfo, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) *tcpip.Error {
+func (n *NIC) writePacket(r RouteInfo, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkt *PacketBuffer) tcpip.Error {
// WritePacket takes ownership of pkt, calculate numBytes first.
numBytes := pkt.Size()
@@ -352,11 +412,11 @@ func (n *NIC) writePacket(r RouteInfo, gso *GSO, protocol tcpip.NetworkProtocolN
}
// WritePackets implements NetworkLinkEndpoint.
-func (n *NIC) WritePackets(r *Route, gso *GSO, pkts PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
+func (n *NIC) WritePackets(r *Route, gso *GSO, pkts PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, tcpip.Error) {
return n.enqueuePacketBuffer(r, gso, protocol, &pkts)
}
-func (n *NIC) writePackets(r RouteInfo, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkts PacketBufferList) (int, *tcpip.Error) {
+func (n *NIC) writePackets(r RouteInfo, gso *GSO, protocol tcpip.NetworkProtocolNumber, pkts PacketBufferList) (int, tcpip.Error) {
for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
pkt.EgressRoute = r
pkt.GSOOptions = gso
@@ -472,15 +532,15 @@ func (n *NIC) getAddressOrCreateTempInner(protocol tcpip.NetworkProtocolNumber,
// addAddress adds a new address to n, so that it starts accepting packets
// targeted at the given address (and network protocol).
-func (n *NIC) addAddress(protocolAddress tcpip.ProtocolAddress, peb PrimaryEndpointBehavior) *tcpip.Error {
+func (n *NIC) addAddress(protocolAddress tcpip.ProtocolAddress, peb PrimaryEndpointBehavior) tcpip.Error {
ep, ok := n.networkEndpoints[protocolAddress.Protocol]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
addressableEndpoint, ok := ep.(AddressableEndpoint)
if !ok {
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
addressEndpoint, err := addressableEndpoint.AddAndAcquirePermanentAddress(protocolAddress.AddressWithPrefix, peb, AddressConfigStatic, false /* deprecated */)
@@ -544,72 +604,75 @@ func (n *NIC) primaryAddress(proto tcpip.NetworkProtocolNumber) tcpip.AddressWit
}
// removeAddress removes an address from n.
-func (n *NIC) removeAddress(addr tcpip.Address) *tcpip.Error {
+func (n *NIC) removeAddress(addr tcpip.Address) tcpip.Error {
for _, ep := range n.networkEndpoints {
addressableEndpoint, ok := ep.(AddressableEndpoint)
if !ok {
continue
}
- if err := addressableEndpoint.RemovePermanentAddress(addr); err == tcpip.ErrBadLocalAddress {
+ switch err := addressableEndpoint.RemovePermanentAddress(addr); err.(type) {
+ case *tcpip.ErrBadLocalAddress:
continue
- } else {
+ default:
return err
}
}
- return tcpip.ErrBadLocalAddress
+ return &tcpip.ErrBadLocalAddress{}
}
-func (n *NIC) getNeighborLinkAddress(addr, localAddr tcpip.Address, linkRes LinkAddressResolver, onResolve func(LinkResolutionResult)) (tcpip.LinkAddress, <-chan struct{}, *tcpip.Error) {
- if n.neigh != nil {
- entry, ch, err := n.neigh.entry(addr, localAddr, linkRes, onResolve)
- return entry.LinkAddr, ch, err
+func (n *NIC) getLinkAddress(addr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, onResolve func(LinkResolutionResult)) tcpip.Error {
+ linkRes, ok := n.linkAddrResolvers[protocol]
+ if !ok {
+ return &tcpip.ErrNotSupported{}
}
- return n.linkAddrCache.get(addr, linkRes, localAddr, n, onResolve)
+ if linkAddr, ok := linkRes.resolver.ResolveStaticAddress(addr); ok {
+ onResolve(LinkResolutionResult{LinkAddress: linkAddr, Success: true})
+ return nil
+ }
+
+ _, _, err := linkRes.getNeighborLinkAddress(addr, localAddr, onResolve)
+ return err
}
-func (n *NIC) neighbors() ([]NeighborEntry, *tcpip.Error) {
- if n.neigh == nil {
- return nil, tcpip.ErrNotSupported
+func (n *NIC) neighbors(protocol tcpip.NetworkProtocolNumber) ([]NeighborEntry, tcpip.Error) {
+ if linkRes, ok := n.linkAddrResolvers[protocol]; ok {
+ return linkRes.neighborTable.neighbors()
}
- return n.neigh.entries(), nil
+ return nil, &tcpip.ErrNotSupported{}
}
-func (n *NIC) addStaticNeighbor(addr tcpip.Address, linkAddress tcpip.LinkAddress) *tcpip.Error {
- if n.neigh == nil {
- return tcpip.ErrNotSupported
+func (n *NIC) addStaticNeighbor(addr tcpip.Address, protocol tcpip.NetworkProtocolNumber, linkAddress tcpip.LinkAddress) tcpip.Error {
+ if linkRes, ok := n.linkAddrResolvers[protocol]; ok {
+ linkRes.neighborTable.addStaticEntry(addr, linkAddress)
+ return nil
}
- n.neigh.addStaticEntry(addr, linkAddress)
- return nil
+ return &tcpip.ErrNotSupported{}
}
-func (n *NIC) removeNeighbor(addr tcpip.Address) *tcpip.Error {
- if n.neigh == nil {
- return tcpip.ErrNotSupported
+func (n *NIC) removeNeighbor(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error {
+ if linkRes, ok := n.linkAddrResolvers[protocol]; ok {
+ return linkRes.neighborTable.remove(addr)
}
- if !n.neigh.removeEntry(addr) {
- return tcpip.ErrBadAddress
- }
- return nil
+ return &tcpip.ErrNotSupported{}
}
-func (n *NIC) clearNeighbors() *tcpip.Error {
- if n.neigh == nil {
- return tcpip.ErrNotSupported
+func (n *NIC) clearNeighbors(protocol tcpip.NetworkProtocolNumber) tcpip.Error {
+ if linkRes, ok := n.linkAddrResolvers[protocol]; ok {
+ return linkRes.neighborTable.removeAll()
}
- n.neigh.clear()
- return nil
+ return &tcpip.ErrNotSupported{}
}
// joinGroup adds a new endpoint for the given multicast address, if none
// exists yet. Otherwise it just increments its count.
-func (n *NIC) joinGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) *tcpip.Error {
+func (n *NIC) joinGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error {
// TODO(b/143102137): When implementing MLD, make sure MLD packets are
// not sent unless a valid link-local address is available for use on n
// as an MLD packet's source address must be a link-local address as
@@ -617,12 +680,12 @@ func (n *NIC) joinGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address
ep, ok := n.networkEndpoints[protocol]
if !ok {
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
gep, ok := ep.(GroupAddressableEndpoint)
if !ok {
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
return gep.JoinGroup(addr)
@@ -630,15 +693,15 @@ func (n *NIC) joinGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address
// leaveGroup decrements the count for the given multicast address, and when it
// reaches zero removes the endpoint for this address.
-func (n *NIC) leaveGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) *tcpip.Error {
+func (n *NIC) leaveGroup(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error {
ep, ok := n.networkEndpoints[protocol]
if !ok {
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
gep, ok := ep.(GroupAddressableEndpoint)
if !ok {
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
return gep.LeaveGroup(addr)
@@ -848,9 +911,8 @@ func (n *NIC) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt
}
}
-// DeliverTransportControlPacket delivers control packets to the appropriate
-// transport protocol endpoint.
-func (n *NIC) DeliverTransportControlPacket(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, typ ControlType, extra uint32, pkt *PacketBuffer) {
+// DeliverTransportError implements TransportDispatcher.
+func (n *NIC) DeliverTransportError(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr TransportError, pkt *PacketBuffer) {
state, ok := n.stack.transportProtocols[trans]
if !ok {
return
@@ -872,7 +934,7 @@ func (n *NIC) DeliverTransportControlPacket(local, remote tcpip.Address, net tcp
}
id := TransportEndpointID{srcPort, local, dstPort, remote}
- if n.stack.demux.deliverControlPacket(n, net, trans, typ, extra, pkt, id) {
+ if n.stack.demux.deliverError(n, net, trans, transErr, pkt, id) {
return
}
}
@@ -888,33 +950,34 @@ func (n *NIC) Name() string {
}
// nudConfigs gets the NUD configurations for n.
-func (n *NIC) nudConfigs() (NUDConfigurations, *tcpip.Error) {
- if n.neigh == nil {
- return NUDConfigurations{}, tcpip.ErrNotSupported
+func (n *NIC) nudConfigs(protocol tcpip.NetworkProtocolNumber) (NUDConfigurations, tcpip.Error) {
+ if linkRes, ok := n.linkAddrResolvers[protocol]; ok {
+ return linkRes.neighborTable.nudConfig()
}
- return n.neigh.config(), nil
+
+ return NUDConfigurations{}, &tcpip.ErrNotSupported{}
}
// setNUDConfigs sets the NUD configurations for n.
//
// Note, if c contains invalid NUD configuration values, it will be fixed to
// use default values for the erroneous values.
-func (n *NIC) setNUDConfigs(c NUDConfigurations) *tcpip.Error {
- if n.neigh == nil {
- return tcpip.ErrNotSupported
+func (n *NIC) setNUDConfigs(protocol tcpip.NetworkProtocolNumber, c NUDConfigurations) tcpip.Error {
+ if linkRes, ok := n.linkAddrResolvers[protocol]; ok {
+ c.resetInvalidFields()
+ return linkRes.neighborTable.setNUDConfig(c)
}
- c.resetInvalidFields()
- n.neigh.setConfig(c)
- return nil
+
+ return &tcpip.ErrNotSupported{}
}
-func (n *NIC) registerPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) *tcpip.Error {
+func (n *NIC) registerPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) tcpip.Error {
n.mu.Lock()
defer n.mu.Unlock()
eps, ok := n.mu.packetEPs[netProto]
if !ok {
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
eps.add(ep)
@@ -941,3 +1004,23 @@ func (n *NIC) isValidForOutgoing(ep AssignableAddressEndpoint) bool {
n.mu.RUnlock()
return n.Enabled() && ep.IsAssigned(spoofing)
}
+
+// HandleNeighborProbe implements NetworkInterface.
+func (n *NIC) HandleNeighborProbe(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, linkAddr tcpip.LinkAddress) tcpip.Error {
+ if l, ok := n.linkAddrResolvers[protocol]; ok {
+ l.neighborTable.handleProbe(addr, linkAddr)
+ return nil
+ }
+
+ return &tcpip.ErrNotSupported{}
+}
+
+// HandleNeighborConfirmation implements NetworkInterface.
+func (n *NIC) HandleNeighborConfirmation(protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, linkAddr tcpip.LinkAddress, flags ReachabilityConfirmationFlags) tcpip.Error {
+ if l, ok := n.linkAddrResolvers[protocol]; ok {
+ l.neighborTable.handleConfirmation(addr, linkAddr, flags)
+ return nil
+ }
+
+ return &tcpip.ErrNotSupported{}
+}
diff --git a/pkg/tcpip/stack/nic_test.go b/pkg/tcpip/stack/nic_test.go
index be5df7b01..9992d6eb4 100644
--- a/pkg/tcpip/stack/nic_test.go
+++ b/pkg/tcpip/stack/nic_test.go
@@ -39,7 +39,7 @@ type testIPv6Endpoint struct {
invalidatedRtr tcpip.Address
}
-func (*testIPv6Endpoint) Enable() *tcpip.Error {
+func (*testIPv6Endpoint) Enable() tcpip.Error {
return nil
}
@@ -65,21 +65,21 @@ func (e *testIPv6Endpoint) MaxHeaderLength() uint16 {
}
// WritePacket implements NetworkEndpoint.WritePacket.
-func (*testIPv6Endpoint) WritePacket(*Route, *GSO, NetworkHeaderParams, *PacketBuffer) *tcpip.Error {
+func (*testIPv6Endpoint) WritePacket(*Route, *GSO, NetworkHeaderParams, *PacketBuffer) tcpip.Error {
return nil
}
// WritePackets implements NetworkEndpoint.WritePackets.
-func (*testIPv6Endpoint) WritePackets(*Route, *GSO, PacketBufferList, NetworkHeaderParams) (int, *tcpip.Error) {
+func (*testIPv6Endpoint) WritePackets(*Route, *GSO, PacketBufferList, NetworkHeaderParams) (int, tcpip.Error) {
// Our tests don't use this so we don't support it.
- return 0, tcpip.ErrNotSupported
+ return 0, &tcpip.ErrNotSupported{}
}
// WriteHeaderIncludedPacket implements
// NetworkEndpoint.WriteHeaderIncludedPacket.
-func (*testIPv6Endpoint) WriteHeaderIncludedPacket(*Route, *PacketBuffer) *tcpip.Error {
+func (*testIPv6Endpoint) WriteHeaderIncludedPacket(*Route, *PacketBuffer) tcpip.Error {
// Our tests don't use this so we don't support it.
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
// HandlePacket implements NetworkEndpoint.HandlePacket.
@@ -111,8 +111,6 @@ type testIPv6EndpointStats struct{}
// IsNetworkEndpointStats implements stack.NetworkEndpointStats.
func (*testIPv6EndpointStats) IsNetworkEndpointStats() {}
-var _ LinkAddressResolver = (*testIPv6Protocol)(nil)
-
// We use this instead of ipv6.protocol because the ipv6 package depends on
// the stack package which this test lives in, causing a cyclic dependency.
type testIPv6Protocol struct{}
@@ -139,7 +137,7 @@ func (*testIPv6Protocol) ParseAddresses(v buffer.View) (src, dst tcpip.Address)
}
// NewEndpoint implements NetworkProtocol.NewEndpoint.
-func (p *testIPv6Protocol) NewEndpoint(nic NetworkInterface, _ LinkAddressCache, _ NUDHandler, _ TransportDispatcher) NetworkEndpoint {
+func (p *testIPv6Protocol) NewEndpoint(nic NetworkInterface, _ TransportDispatcher) NetworkEndpoint {
e := &testIPv6Endpoint{
nic: nic,
protocol: p,
@@ -149,12 +147,12 @@ func (p *testIPv6Protocol) NewEndpoint(nic NetworkInterface, _ LinkAddressCache,
}
// SetOption implements NetworkProtocol.SetOption.
-func (*testIPv6Protocol) SetOption(tcpip.SettableNetworkProtocolOption) *tcpip.Error {
+func (*testIPv6Protocol) SetOption(tcpip.SettableNetworkProtocolOption) tcpip.Error {
return nil
}
// Option implements NetworkProtocol.Option.
-func (*testIPv6Protocol) Option(tcpip.GettableNetworkProtocolOption) *tcpip.Error {
+func (*testIPv6Protocol) Option(tcpip.GettableNetworkProtocolOption) tcpip.Error {
return nil
}
@@ -169,24 +167,6 @@ func (*testIPv6Protocol) Parse(*PacketBuffer) (tcpip.TransportProtocolNumber, bo
return 0, false, false
}
-// LinkAddressProtocol implements LinkAddressResolver.
-func (*testIPv6Protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
- return header.IPv6ProtocolNumber
-}
-
-// LinkAddressRequest implements LinkAddressResolver.
-func (*testIPv6Protocol) LinkAddressRequest(_, _ tcpip.Address, _ tcpip.LinkAddress, _ NetworkInterface) *tcpip.Error {
- return nil
-}
-
-// ResolveStaticAddress implements LinkAddressResolver.
-func (*testIPv6Protocol) ResolveStaticAddress(addr tcpip.Address) (tcpip.LinkAddress, bool) {
- if header.IsV6MulticastAddress(addr) {
- return header.EthernetAddressFromMulticastIPv6Address(addr), true
- }
- return "", false
-}
-
func TestDisabledRxStatsWhenNICDisabled(t *testing.T) {
// When the NIC is disabled, the only field that matters is the stats field.
// This test is limited to stats counter checks.
diff --git a/pkg/tcpip/stack/nud.go b/pkg/tcpip/stack/nud.go
index 12d67409a..5a94e9ac6 100644
--- a/pkg/tcpip/stack/nud.go
+++ b/pkg/tcpip/stack/nud.go
@@ -161,25 +161,6 @@ type ReachabilityConfirmationFlags struct {
IsRouter bool
}
-// NUDHandler communicates external events to the Neighbor Unreachability
-// Detection state machine, which is implemented per-interface. This is used by
-// network endpoints to inform the Neighbor Cache of probes and confirmations.
-type NUDHandler interface {
- // HandleProbe processes an incoming neighbor probe (e.g. ARP request or
- // Neighbor Solicitation for ARP or NDP, respectively). Validation of the
- // probe needs to be performed before calling this function since the
- // Neighbor Cache doesn't have access to view the NIC's assigned addresses.
- HandleProbe(remoteAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, linkRes LinkAddressResolver)
-
- // HandleConfirmation processes an incoming neighbor confirmation (e.g. ARP
- // reply or Neighbor Advertisement for ARP or NDP, respectively).
- HandleConfirmation(addr tcpip.Address, linkAddr tcpip.LinkAddress, flags ReachabilityConfirmationFlags)
-
- // HandleUpperLevelConfirmation processes an incoming upper-level protocol
- // (e.g. TCP acknowledgements) reachability confirmation.
- HandleUpperLevelConfirmation(addr tcpip.Address)
-}
-
// NUDConfigurations is the NUD configurations for the netstack. This is used
// by the neighbor cache to operate the NUD state machine on each device in the
// local network.
diff --git a/pkg/tcpip/stack/nud_test.go b/pkg/tcpip/stack/nud_test.go
index 7bca1373e..e9acef6a2 100644
--- a/pkg/tcpip/stack/nud_test.go
+++ b/pkg/tcpip/stack/nud_test.go
@@ -19,7 +19,9 @@ import (
"testing"
"time"
+ "github.com/google/go-cmp/cmp"
"gvisor.dev/gvisor/pkg/tcpip"
+ "gvisor.dev/gvisor/pkg/tcpip/faketime"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
"gvisor.dev/gvisor/pkg/tcpip/stack"
@@ -52,80 +54,146 @@ func (f *fakeRand) Float32() float32 {
return f.num
}
-// TestSetNUDConfigurationFailsForBadNICID tests to make sure we get an error if
-// we attempt to update NUD configurations using an invalid NICID.
-func TestSetNUDConfigurationFailsForBadNICID(t *testing.T) {
- s := stack.New(stack.Options{
- // A neighbor cache is required to store NUDConfigurations. The networking
- // stack will only allocate neighbor caches if a protocol providing link
- // address resolution is specified (e.g. ARP or IPv6).
- NetworkProtocols: []stack.NetworkProtocolFactory{ipv6.NewProtocol},
- UseNeighborCache: true,
- })
+func TestNUDFunctions(t *testing.T) {
+ const nicID = 1
- // No NIC with ID 1 yet.
- config := stack.NUDConfigurations{}
- if err := s.SetNUDConfigurations(1, config); err != tcpip.ErrUnknownNICID {
- t.Fatalf("got s.SetNDPConfigurations(1, %+v) = %v, want = %s", config, err, tcpip.ErrUnknownNICID)
+ tests := []struct {
+ name string
+ nicID tcpip.NICID
+ netProtoFactory []stack.NetworkProtocolFactory
+ extraLinkCapabilities stack.LinkEndpointCapabilities
+ expectedErr tcpip.Error
+ }{
+ {
+ name: "Invalid NICID",
+ nicID: nicID + 1,
+ netProtoFactory: []stack.NetworkProtocolFactory{ipv6.NewProtocol},
+ extraLinkCapabilities: stack.CapabilityResolutionRequired,
+ expectedErr: &tcpip.ErrUnknownNICID{},
+ },
+ {
+ name: "No network protocol",
+ nicID: nicID,
+ expectedErr: &tcpip.ErrNotSupported{},
+ },
+ {
+ name: "With IPv6",
+ nicID: nicID,
+ netProtoFactory: []stack.NetworkProtocolFactory{ipv6.NewProtocol},
+ expectedErr: &tcpip.ErrNotSupported{},
+ },
+ {
+ name: "With resolution capability",
+ nicID: nicID,
+ extraLinkCapabilities: stack.CapabilityResolutionRequired,
+ expectedErr: &tcpip.ErrNotSupported{},
+ },
+ {
+ name: "With IPv6 and resolution capability",
+ nicID: nicID,
+ netProtoFactory: []stack.NetworkProtocolFactory{ipv6.NewProtocol},
+ extraLinkCapabilities: stack.CapabilityResolutionRequired,
+ },
}
-}
-// TestNUDConfigurationFailsForNotSupported tests to make sure we get a
-// NotSupported error if we attempt to retrieve NUD configurations when the
-// stack doesn't support NUD.
-//
-// The stack will report to not support NUD if a neighbor cache for a given NIC
-// is not allocated. The networking stack will only allocate neighbor caches if
-// a protocol providing link address resolution is specified (e.g. ARP, IPv6).
-func TestNUDConfigurationFailsForNotSupported(t *testing.T) {
- const nicID = 1
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ clock := faketime.NewManualClock()
+ s := stack.New(stack.Options{
+ NUDConfigs: stack.DefaultNUDConfigurations(),
+ UseNeighborCache: true,
+ NetworkProtocols: test.netProtoFactory,
+ Clock: clock,
+ })
- e := channel.New(0, 1280, linkAddr1)
- e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
+ e := channel.New(0, 0, linkAddr1)
+ e.LinkEPCapabilities &^= stack.CapabilityResolutionRequired
+ e.LinkEPCapabilities |= test.extraLinkCapabilities
- s := stack.New(stack.Options{
- NUDConfigs: stack.DefaultNUDConfigurations(),
- UseNeighborCache: true,
- })
- if err := s.CreateNIC(nicID, e); err != nil {
- t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
- }
- if _, err := s.NUDConfigurations(nicID); err != tcpip.ErrNotSupported {
- t.Fatalf("got s.NDPConfigurations(%d) = %v, want = %s", nicID, err, tcpip.ErrNotSupported)
- }
-}
+ if err := s.CreateNIC(nicID, e); err != nil {
+ t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
+ }
-// TestNUDConfigurationFailsForNotSupported tests to make sure we get a
-// NotSupported error if we attempt to set NUD configurations when the stack
-// doesn't support NUD.
-//
-// The stack will report to not support NUD if a neighbor cache for a given NIC
-// is not allocated. The networking stack will only allocate neighbor caches if
-// a protocol providing link address resolution is specified (e.g. ARP, IPv6).
-func TestSetNUDConfigurationFailsForNotSupported(t *testing.T) {
- const nicID = 1
+ configs := stack.DefaultNUDConfigurations()
+ configs.BaseReachableTime = time.Hour
- e := channel.New(0, 1280, linkAddr1)
- e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
+ {
+ err := s.SetNUDConfigurations(test.nicID, ipv6.ProtocolNumber, configs)
+ if diff := cmp.Diff(test.expectedErr, err); diff != "" {
+ t.Errorf("s.SetNUDConfigurations(%d, %d, _) error mismatch (-want +got):\n%s", test.nicID, ipv6.ProtocolNumber, diff)
+ }
+ }
- s := stack.New(stack.Options{
- NUDConfigs: stack.DefaultNUDConfigurations(),
- UseNeighborCache: true,
- })
- if err := s.CreateNIC(nicID, e); err != nil {
- t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
- }
+ {
+ gotConfigs, err := s.NUDConfigurations(test.nicID, ipv6.ProtocolNumber)
+ if diff := cmp.Diff(test.expectedErr, err); diff != "" {
+ t.Errorf("s.NUDConfigurations(%d, %d) error mismatch (-want +got):\n%s", test.nicID, ipv6.ProtocolNumber, diff)
+ } else if test.expectedErr == nil {
+ if diff := cmp.Diff(configs, gotConfigs); diff != "" {
+ t.Errorf("got configs mismatch (-want +got):\n%s", diff)
+ }
+ }
+ }
- config := stack.NUDConfigurations{}
- if err := s.SetNUDConfigurations(nicID, config); err != tcpip.ErrNotSupported {
- t.Fatalf("got s.SetNDPConfigurations(%d, %+v) = %v, want = %s", nicID, config, err, tcpip.ErrNotSupported)
+ for _, addr := range []tcpip.Address{llAddr1, llAddr2} {
+ {
+ err := s.AddStaticNeighbor(test.nicID, ipv6.ProtocolNumber, addr, linkAddr1)
+ if diff := cmp.Diff(test.expectedErr, err); diff != "" {
+ t.Errorf("s.AddStaticNeighbor(%d, %d, %s, %s) error mismatch (-want +got):\n%s", test.nicID, ipv6.ProtocolNumber, addr, linkAddr1, diff)
+ }
+ }
+ }
+
+ {
+ wantErr := test.expectedErr
+ for i := 0; i < 2; i++ {
+ {
+ err := s.RemoveNeighbor(test.nicID, ipv6.ProtocolNumber, llAddr1)
+ if diff := cmp.Diff(wantErr, err); diff != "" {
+ t.Errorf("s.RemoveNeighbor(%d, %d, '') error mismatch (-want +got):\n%s", test.nicID, ipv6.ProtocolNumber, diff)
+ }
+ }
+
+ if test.expectedErr != nil {
+ break
+ }
+
+ // Removing a neighbor that does not exist should give us a bad address
+ // error.
+ wantErr = &tcpip.ErrBadAddress{}
+ }
+ }
+
+ {
+ neighbors, err := s.Neighbors(test.nicID, ipv6.ProtocolNumber)
+ if diff := cmp.Diff(test.expectedErr, err); diff != "" {
+ t.Errorf("s.Neigbors(%d, %d) error mismatch (-want +got):\n%s", test.nicID, ipv6.ProtocolNumber, diff)
+ } else if test.expectedErr == nil {
+ if diff := cmp.Diff(
+ []stack.NeighborEntry{{Addr: llAddr2, LinkAddr: linkAddr1, State: stack.Static, UpdatedAtNanos: clock.NowNanoseconds()}},
+ neighbors,
+ ); diff != "" {
+ t.Errorf("neighbors mismatch (-want +got):\n%s", diff)
+ }
+ }
+ }
+
+ {
+ err := s.ClearNeighbors(test.nicID, ipv6.ProtocolNumber)
+ if diff := cmp.Diff(test.expectedErr, err); diff != "" {
+ t.Errorf("s.ClearNeigbors(%d, %d) error mismatch (-want +got):\n%s", test.nicID, ipv6.ProtocolNumber, diff)
+ } else if test.expectedErr == nil {
+ if neighbors, err := s.Neighbors(test.nicID, ipv6.ProtocolNumber); err != nil {
+ t.Errorf("s.Neighbors(%d, %d): %s", test.nicID, ipv6.ProtocolNumber, err)
+ } else if len(neighbors) != 0 {
+ t.Errorf("got len(neighbors) = %d, want = 0; neighbors = %#v", len(neighbors), neighbors)
+ }
+ }
+ }
+ })
}
}
-// TestDefaultNUDConfigurationIsValid verifies that calling
-// resetInvalidFields() on the result of DefaultNUDConfigurations() does not
-// change anything. DefaultNUDConfigurations() should return a valid
-// NUDConfigurations.
func TestDefaultNUDConfigurations(t *testing.T) {
const nicID = 1
@@ -143,12 +211,12 @@ func TestDefaultNUDConfigurations(t *testing.T) {
if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- c, err := s.NUDConfigurations(nicID)
+ c, err := s.NUDConfigurations(nicID, ipv6.ProtocolNumber)
if err != nil {
- t.Fatalf("got stack.NUDConfigurations(%d) = %s", nicID, err)
+ t.Fatalf("got stack.NUDConfigurations(%d, %d) = %s", nicID, ipv6.ProtocolNumber, err)
}
if got, want := c, stack.DefaultNUDConfigurations(); got != want {
- t.Errorf("got stack.NUDConfigurations(%d) = %+v, want = %+v", nicID, got, want)
+ t.Errorf("got stack.NUDConfigurations(%d, %d) = %+v, want = %+v", nicID, ipv6.ProtocolNumber, got, want)
}
}
@@ -198,9 +266,9 @@ func TestNUDConfigurationsBaseReachableTime(t *testing.T) {
if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- sc, err := s.NUDConfigurations(nicID)
+ sc, err := s.NUDConfigurations(nicID, ipv6.ProtocolNumber)
if err != nil {
- t.Fatalf("got stack.NUDConfigurations(%d) = %s", nicID, err)
+ t.Fatalf("got stack.NUDConfigurations(%d, %d) = %s", nicID, ipv6.ProtocolNumber, err)
}
if got := sc.BaseReachableTime; got != test.want {
t.Errorf("got BaseReachableTime = %q, want = %q", got, test.want)
@@ -255,9 +323,9 @@ func TestNUDConfigurationsMinRandomFactor(t *testing.T) {
if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- sc, err := s.NUDConfigurations(nicID)
+ sc, err := s.NUDConfigurations(nicID, ipv6.ProtocolNumber)
if err != nil {
- t.Fatalf("got stack.NUDConfigurations(%d) = %s", nicID, err)
+ t.Fatalf("got stack.NUDConfigurations(%d, %d) = %s", nicID, ipv6.ProtocolNumber, err)
}
if got := sc.MinRandomFactor; got != test.want {
t.Errorf("got MinRandomFactor = %f, want = %f", got, test.want)
@@ -335,9 +403,9 @@ func TestNUDConfigurationsMaxRandomFactor(t *testing.T) {
if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- sc, err := s.NUDConfigurations(nicID)
+ sc, err := s.NUDConfigurations(nicID, ipv6.ProtocolNumber)
if err != nil {
- t.Fatalf("got stack.NUDConfigurations(%d) = %s", nicID, err)
+ t.Fatalf("got stack.NUDConfigurations(%d, %d) = %s", nicID, ipv6.ProtocolNumber, err)
}
if got := sc.MaxRandomFactor; got != test.want {
t.Errorf("got MaxRandomFactor = %f, want = %f", got, test.want)
@@ -397,9 +465,9 @@ func TestNUDConfigurationsRetransmitTimer(t *testing.T) {
if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- sc, err := s.NUDConfigurations(nicID)
+ sc, err := s.NUDConfigurations(nicID, ipv6.ProtocolNumber)
if err != nil {
- t.Fatalf("got stack.NUDConfigurations(%d) = %s", nicID, err)
+ t.Fatalf("got stack.NUDConfigurations(%d, %d) = %s", nicID, ipv6.ProtocolNumber, err)
}
if got := sc.RetransmitTimer; got != test.want {
t.Errorf("got RetransmitTimer = %q, want = %q", got, test.want)
@@ -449,9 +517,9 @@ func TestNUDConfigurationsDelayFirstProbeTime(t *testing.T) {
if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- sc, err := s.NUDConfigurations(nicID)
+ sc, err := s.NUDConfigurations(nicID, ipv6.ProtocolNumber)
if err != nil {
- t.Fatalf("got stack.NUDConfigurations(%d) = %s", nicID, err)
+ t.Fatalf("got stack.NUDConfigurations(%d, %d) = %s", nicID, ipv6.ProtocolNumber, err)
}
if got := sc.DelayFirstProbeTime; got != test.want {
t.Errorf("got DelayFirstProbeTime = %q, want = %q", got, test.want)
@@ -501,9 +569,9 @@ func TestNUDConfigurationsMaxMulticastProbes(t *testing.T) {
if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- sc, err := s.NUDConfigurations(nicID)
+ sc, err := s.NUDConfigurations(nicID, ipv6.ProtocolNumber)
if err != nil {
- t.Fatalf("got stack.NUDConfigurations(%d) = %s", nicID, err)
+ t.Fatalf("got stack.NUDConfigurations(%d, %d) = %s", nicID, ipv6.ProtocolNumber, err)
}
if got := sc.MaxMulticastProbes; got != test.want {
t.Errorf("got MaxMulticastProbes = %q, want = %q", got, test.want)
@@ -553,9 +621,9 @@ func TestNUDConfigurationsMaxUnicastProbes(t *testing.T) {
if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- sc, err := s.NUDConfigurations(nicID)
+ sc, err := s.NUDConfigurations(nicID, ipv6.ProtocolNumber)
if err != nil {
- t.Fatalf("got stack.NUDConfigurations(%d) = %s", nicID, err)
+ t.Fatalf("got stack.NUDConfigurations(%d, %d) = %s", nicID, ipv6.ProtocolNumber, err)
}
if got := sc.MaxUnicastProbes; got != test.want {
t.Errorf("got MaxUnicastProbes = %q, want = %q", got, test.want)
diff --git a/pkg/tcpip/stack/packet_buffer.go b/pkg/tcpip/stack/packet_buffer.go
index 9d4fc3e48..4f013b212 100644
--- a/pkg/tcpip/stack/packet_buffer.go
+++ b/pkg/tcpip/stack/packet_buffer.go
@@ -187,6 +187,12 @@ func (pk *PacketBuffer) Size() int {
return pk.HeaderSize() + pk.Data.Size()
}
+// MemSize returns the estimation size of the pk in memory, including backing
+// buffer data.
+func (pk *PacketBuffer) MemSize() int {
+ return pk.HeaderSize() + pk.Data.MemSize() + packetBufferStructSize
+}
+
// Views returns the underlying storage of the whole packet.
func (pk *PacketBuffer) Views() []buffer.View {
// Optimization for outbound packets that headers are in pk.header.
diff --git a/pkg/tcpip/stack/packet_buffer_unsafe.go b/pkg/tcpip/stack/packet_buffer_unsafe.go
new file mode 100644
index 000000000..ee3d47270
--- /dev/null
+++ b/pkg/tcpip/stack/packet_buffer_unsafe.go
@@ -0,0 +1,19 @@
+// Copyright 2021 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 stack
+
+import "unsafe"
+
+const packetBufferStructSize = int(unsafe.Sizeof(PacketBuffer{}))
diff --git a/pkg/tcpip/stack/pending_packets.go b/pkg/tcpip/stack/pending_packets.go
index c4769b17e..1c651e216 100644
--- a/pkg/tcpip/stack/pending_packets.go
+++ b/pkg/tcpip/stack/pending_packets.go
@@ -114,26 +114,12 @@ func (f *packetsPendingLinkResolution) dequeue(ch <-chan struct{}, linkAddr tcpi
}
}
-func (f *packetsPendingLinkResolution) writePacketBuffer(r RouteInfo, gso *GSO, proto tcpip.NetworkProtocolNumber, pkt pendingPacketBuffer) (int, *tcpip.Error) {
- switch pkt := pkt.(type) {
- case *PacketBuffer:
- if err := f.nic.writePacket(r, gso, proto, pkt); err != nil {
- return 0, err
- }
- return 1, nil
- case *PacketBufferList:
- return f.nic.writePackets(r, gso, proto, *pkt)
- default:
- panic(fmt.Sprintf("unrecognized pending packet buffer type = %T", pkt))
- }
-}
-
// enqueue a packet to be sent once link resolution completes.
//
// If the maximum number of pending resolutions is reached, the packets
// associated with the oldest link resolution will be dequeued as if they failed
// link resolution.
-func (f *packetsPendingLinkResolution) enqueue(r *Route, gso *GSO, proto tcpip.NetworkProtocolNumber, pkt pendingPacketBuffer) (int, *tcpip.Error) {
+func (f *packetsPendingLinkResolution) enqueue(r *Route, gso *GSO, proto tcpip.NetworkProtocolNumber, pkt pendingPacketBuffer) (int, tcpip.Error) {
f.mu.Lock()
// Make sure we attempt resolution while holding f's lock so that we avoid
// a race where link resolution completes before we enqueue the packets.
@@ -146,13 +132,13 @@ func (f *packetsPendingLinkResolution) enqueue(r *Route, gso *GSO, proto tcpip.N
// To make sure B does not interleave with A and C, we make sure A and C are
// done while holding the lock.
routeInfo, ch, err := r.resolvedFields(nil)
- switch err {
+ switch err.(type) {
case nil:
// The route resolved immediately, so we don't need to wait for link
// resolution to send the packet.
f.mu.Unlock()
- return f.writePacketBuffer(routeInfo, gso, proto, pkt)
- case tcpip.ErrWouldBlock:
+ return f.nic.writePacketBuffer(routeInfo, gso, proto, pkt)
+ case *tcpip.ErrWouldBlock:
// We need to wait for link resolution to complete.
default:
f.mu.Unlock()
@@ -225,7 +211,7 @@ func (f *packetsPendingLinkResolution) dequeuePackets(packets []pendingPacket, l
for _, p := range packets {
if success {
p.routeInfo.RemoteLinkAddress = linkAddr
- _, _ = f.writePacketBuffer(p.routeInfo, p.gso, p.proto, p.pkt)
+ _, _ = f.nic.writePacketBuffer(p.routeInfo, p.gso, p.proto, p.pkt)
} else {
f.incrementOutgoingPacketErrors(p.proto, p.pkt)
diff --git a/pkg/tcpip/stack/registration.go b/pkg/tcpip/stack/registration.go
index 33df192aa..d589f798d 100644
--- a/pkg/tcpip/stack/registration.go
+++ b/pkg/tcpip/stack/registration.go
@@ -49,31 +49,6 @@ type TransportEndpointID struct {
RemoteAddress tcpip.Address
}
-// ControlType is the type of network control message.
-type ControlType int
-
-// The following are the allowed values for ControlType values.
-// TODO(http://gvisor.dev/issue/3210): Support time exceeded messages.
-const (
- // ControlAddressUnreachable indicates that an IPv6 packet did not reach its
- // destination as the destination address was unreachable.
- //
- // This maps to the ICMPv6 Destination Ureachable Code 3 error; see
- // RFC 4443 section 3.1 for more details.
- ControlAddressUnreachable ControlType = iota
- ControlNetworkUnreachable
- // ControlNoRoute indicates that an IPv4 packet did not reach its destination
- // because the destination host was unreachable.
- //
- // This maps to the ICMPv4 Destination Ureachable Code 1 error; see
- // RFC 791's Destination Unreachable Message section (page 4) for more
- // details.
- ControlNoRoute
- ControlPacketTooBig
- ControlPortUnreachable
- ControlUnknown
-)
-
// NetworkPacketInfo holds information about a network layer packet.
type NetworkPacketInfo struct {
// LocalAddressBroadcast is true if the packet's local address is a broadcast
@@ -81,6 +56,39 @@ type NetworkPacketInfo struct {
LocalAddressBroadcast bool
}
+// TransportErrorKind enumerates error types that are handled by the transport
+// layer.
+type TransportErrorKind int
+
+const (
+ // PacketTooBigTransportError indicates that a packet did not reach its
+ // destination because a link on the path to the destination had an MTU that
+ // was too small to carry the packet.
+ PacketTooBigTransportError TransportErrorKind = iota
+
+ // DestinationHostUnreachableTransportError indicates that the destination
+ // host was unreachable.
+ DestinationHostUnreachableTransportError
+
+ // DestinationPortUnreachableTransportError indicates that a packet reached
+ // the destination host, but the transport protocol was not active on the
+ // destination port.
+ DestinationPortUnreachableTransportError
+
+ // DestinationNetworkUnreachableTransportError indicates that the destination
+ // network was unreachable.
+ DestinationNetworkUnreachableTransportError
+)
+
+// TransportError is a marker interface for errors that may be handled by the
+// transport layer.
+type TransportError interface {
+ tcpip.SockErrorCause
+
+ // Kind returns the type of the transport error.
+ Kind() TransportErrorKind
+}
+
// TransportEndpoint is the interface that needs to be implemented by transport
// protocol (e.g., tcp, udp) endpoints that can handle packets.
type TransportEndpoint interface {
@@ -93,10 +101,10 @@ type TransportEndpoint interface {
// HandlePacket takes ownership of the packet.
HandlePacket(TransportEndpointID, *PacketBuffer)
- // HandleControlPacket is called by the stack when new control (e.g.
- // ICMP) packets arrive to this transport endpoint.
- // HandleControlPacket takes ownership of pkt.
- HandleControlPacket(typ ControlType, extra uint32, pkt *PacketBuffer)
+ // HandleError is called when the transport endpoint receives an error.
+ //
+ // HandleError takes ownership of the packet buffer.
+ HandleError(TransportError, *PacketBuffer)
// Abort initiates an expedited endpoint teardown. It puts the endpoint
// in a closed state and frees all resources associated with it. This
@@ -172,10 +180,10 @@ type TransportProtocol interface {
Number() tcpip.TransportProtocolNumber
// NewEndpoint creates a new endpoint of the transport protocol.
- NewEndpoint(netProto tcpip.NetworkProtocolNumber, waitQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error)
+ NewEndpoint(netProto tcpip.NetworkProtocolNumber, waitQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error)
// NewRawEndpoint creates a new raw endpoint of the transport protocol.
- NewRawEndpoint(netProto tcpip.NetworkProtocolNumber, waitQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error)
+ NewRawEndpoint(netProto tcpip.NetworkProtocolNumber, waitQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error)
// MinimumPacketSize returns the minimum valid packet size of this
// transport protocol. The stack automatically drops any packets smaller
@@ -184,7 +192,7 @@ type TransportProtocol interface {
// ParsePorts returns the source and destination ports stored in a
// packet of this protocol.
- ParsePorts(v buffer.View) (src, dst uint16, err *tcpip.Error)
+ ParsePorts(v buffer.View) (src, dst uint16, err tcpip.Error)
// HandleUnknownDestinationPacket handles packets targeted at this
// protocol that don't match any existing endpoint. For example,
@@ -197,12 +205,12 @@ type TransportProtocol interface {
// SetOption allows enabling/disabling protocol specific features.
// SetOption returns an error if the option is not supported or the
// provided option value is invalid.
- SetOption(option tcpip.SettableTransportProtocolOption) *tcpip.Error
+ SetOption(option tcpip.SettableTransportProtocolOption) tcpip.Error
// Option allows retrieving protocol specific option values.
// Option returns an error if the option is not supported or the
// provided option value is invalid.
- Option(option tcpip.GettableTransportProtocolOption) *tcpip.Error
+ Option(option tcpip.GettableTransportProtocolOption) tcpip.Error
// Close requests that any worker goroutines owned by the protocol
// stop.
@@ -248,14 +256,11 @@ type TransportDispatcher interface {
// DeliverTransportPacket takes ownership of the packet.
DeliverTransportPacket(tcpip.TransportProtocolNumber, *PacketBuffer) TransportPacketDisposition
- // DeliverTransportControlPacket delivers control packets to the
- // appropriate transport protocol endpoint.
- //
- // pkt.NetworkHeader must be set before calling
- // DeliverTransportControlPacket.
+ // DeliverTransportError delivers an error to the appropriate transport
+ // endpoint.
//
- // DeliverTransportControlPacket takes ownership of pkt.
- DeliverTransportControlPacket(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, typ ControlType, extra uint32, pkt *PacketBuffer)
+ // DeliverTransportError takes ownership of the packet buffer.
+ DeliverTransportError(local, remote tcpip.Address, _ tcpip.NetworkProtocolNumber, _ tcpip.TransportProtocolNumber, _ TransportError, _ *PacketBuffer)
}
// PacketLooping specifies where an outbound packet should be sent.
@@ -289,10 +294,10 @@ type NetworkHeaderParams struct {
// endpoints may associate themselves with the same identifier (group address).
type GroupAddressableEndpoint interface {
// JoinGroup joins the specified group.
- JoinGroup(group tcpip.Address) *tcpip.Error
+ JoinGroup(group tcpip.Address) tcpip.Error
// LeaveGroup attempts to leave the specified group.
- LeaveGroup(group tcpip.Address) *tcpip.Error
+ LeaveGroup(group tcpip.Address) tcpip.Error
// IsInGroup returns true if the endpoint is a member of the specified group.
IsInGroup(group tcpip.Address) bool
@@ -440,17 +445,17 @@ func (k AddressKind) IsPermanent() bool {
type AddressableEndpoint interface {
// AddAndAcquirePermanentAddress adds the passed permanent address.
//
- // Returns tcpip.ErrDuplicateAddress if the address exists.
+ // Returns *tcpip.ErrDuplicateAddress if the address exists.
//
// Acquires and returns the AddressEndpoint for the added address.
- AddAndAcquirePermanentAddress(addr tcpip.AddressWithPrefix, peb PrimaryEndpointBehavior, configType AddressConfigType, deprecated bool) (AddressEndpoint, *tcpip.Error)
+ AddAndAcquirePermanentAddress(addr tcpip.AddressWithPrefix, peb PrimaryEndpointBehavior, configType AddressConfigType, deprecated bool) (AddressEndpoint, tcpip.Error)
// RemovePermanentAddress removes the passed address if it is a permanent
// address.
//
- // Returns tcpip.ErrBadLocalAddress if the endpoint does not have the passed
+ // Returns *tcpip.ErrBadLocalAddress if the endpoint does not have the passed
// permanent address.
- RemovePermanentAddress(addr tcpip.Address) *tcpip.Error
+ RemovePermanentAddress(addr tcpip.Address) tcpip.Error
// MainAddress returns the endpoint's primary permanent address.
MainAddress() tcpip.AddressWithPrefix
@@ -512,14 +517,14 @@ type NetworkInterface interface {
Promiscuous() bool
// WritePacketToRemote writes the packet to the given remote link address.
- WritePacketToRemote(tcpip.LinkAddress, *GSO, tcpip.NetworkProtocolNumber, *PacketBuffer) *tcpip.Error
+ WritePacketToRemote(tcpip.LinkAddress, *GSO, tcpip.NetworkProtocolNumber, *PacketBuffer) tcpip.Error
// WritePacket writes a packet with the given protocol through the given
// route.
//
// WritePacket takes ownership of the packet buffer. The packet buffer's
// network and transport header must be set.
- WritePacket(*Route, *GSO, tcpip.NetworkProtocolNumber, *PacketBuffer) *tcpip.Error
+ WritePacket(*Route, *GSO, tcpip.NetworkProtocolNumber, *PacketBuffer) tcpip.Error
// WritePackets writes packets with the given protocol through the given
// route. Must not be called with an empty list of packet buffers.
@@ -529,7 +534,18 @@ type NetworkInterface interface {
// Right now, WritePackets is used only when the software segmentation
// offload is enabled. If it will be used for something else, syscall filters
// may need to be updated.
- WritePackets(*Route, *GSO, PacketBufferList, tcpip.NetworkProtocolNumber) (int, *tcpip.Error)
+ WritePackets(*Route, *GSO, PacketBufferList, tcpip.NetworkProtocolNumber) (int, tcpip.Error)
+
+ // HandleNeighborProbe processes an incoming neighbor probe (e.g. ARP
+ // request or NDP Neighbor Solicitation).
+ //
+ // HandleNeighborProbe assumes that the probe is valid for the network
+ // interface the probe was received on.
+ HandleNeighborProbe(tcpip.NetworkProtocolNumber, tcpip.Address, tcpip.LinkAddress) tcpip.Error
+
+ // HandleNeighborConfirmation processes an incoming neighbor confirmation
+ // (e.g. ARP reply or NDP Neighbor Advertisement).
+ HandleNeighborConfirmation(tcpip.NetworkProtocolNumber, tcpip.Address, tcpip.LinkAddress, ReachabilityConfirmationFlags) tcpip.Error
}
// LinkResolvableNetworkEndpoint handles link resolution events.
@@ -547,8 +563,8 @@ type NetworkEndpoint interface {
// Must only be called when the stack is in a state that allows the endpoint
// to send and receive packets.
//
- // Returns tcpip.ErrNotPermitted if the endpoint cannot be enabled.
- Enable() *tcpip.Error
+ // Returns *tcpip.ErrNotPermitted if the endpoint cannot be enabled.
+ Enable() tcpip.Error
// Enabled returns true if the endpoint is enabled.
Enabled() bool
@@ -574,16 +590,16 @@ type NetworkEndpoint interface {
// WritePacket writes a packet to the given destination address and
// protocol. It takes ownership of pkt. pkt.TransportHeader must have
// already been set.
- WritePacket(r *Route, gso *GSO, params NetworkHeaderParams, pkt *PacketBuffer) *tcpip.Error
+ WritePacket(r *Route, gso *GSO, params NetworkHeaderParams, pkt *PacketBuffer) tcpip.Error
// WritePackets writes packets to the given destination address and
// protocol. pkts must not be zero length. It takes ownership of pkts and
// underlying packets.
- WritePackets(r *Route, gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, *tcpip.Error)
+ WritePackets(r *Route, gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, tcpip.Error)
// WriteHeaderIncludedPacket writes a packet that includes a network
// header to the given destination address. It takes ownership of pkt.
- WriteHeaderIncludedPacket(r *Route, pkt *PacketBuffer) *tcpip.Error
+ WriteHeaderIncludedPacket(r *Route, pkt *PacketBuffer) tcpip.Error
// HandlePacket is called by the link layer when new packets arrive to
// this network endpoint. It sets pkt.NetworkHeader.
@@ -649,17 +665,17 @@ type NetworkProtocol interface {
ParseAddresses(v buffer.View) (src, dst tcpip.Address)
// NewEndpoint creates a new endpoint of this protocol.
- NewEndpoint(nic NetworkInterface, linkAddrCache LinkAddressCache, nud NUDHandler, dispatcher TransportDispatcher) NetworkEndpoint
+ NewEndpoint(nic NetworkInterface, dispatcher TransportDispatcher) NetworkEndpoint
// SetOption allows enabling/disabling protocol specific features.
// SetOption returns an error if the option is not supported or the
// provided option value is invalid.
- SetOption(option tcpip.SettableNetworkProtocolOption) *tcpip.Error
+ SetOption(option tcpip.SettableNetworkProtocolOption) tcpip.Error
// Option allows retrieving protocol specific option values.
// Option returns an error if the option is not supported or the
// provided option value is invalid.
- Option(option tcpip.GettableNetworkProtocolOption) *tcpip.Error
+ Option(option tcpip.GettableNetworkProtocolOption) tcpip.Error
// Close requests that any worker goroutines owned by the protocol
// stop.
@@ -796,7 +812,7 @@ type LinkEndpoint interface {
// To participate in transparent bridging, a LinkEndpoint implementation
// should call eth.Encode with header.EthernetFields.SrcAddr set to
// r.LocalLinkAddress if it is provided.
- WritePacket(RouteInfo, *GSO, tcpip.NetworkProtocolNumber, *PacketBuffer) *tcpip.Error
+ WritePacket(RouteInfo, *GSO, tcpip.NetworkProtocolNumber, *PacketBuffer) tcpip.Error
// WritePackets writes packets with the given protocol and route. Must not be
// called with an empty list of packet buffers.
@@ -806,7 +822,7 @@ type LinkEndpoint interface {
// Right now, WritePackets is used only when the software segmentation
// offload is enabled. If it will be used for something else, syscall filters
// may need to be updated.
- WritePackets(RouteInfo, *GSO, PacketBufferList, tcpip.NetworkProtocolNumber) (int, *tcpip.Error)
+ WritePackets(RouteInfo, *GSO, PacketBufferList, tcpip.NetworkProtocolNumber) (int, tcpip.Error)
}
// InjectableLinkEndpoint is a LinkEndpoint where inbound packets are
@@ -821,19 +837,15 @@ type InjectableLinkEndpoint interface {
// link.
//
// dest is used by endpoints with multiple raw destinations.
- InjectOutbound(dest tcpip.Address, packet []byte) *tcpip.Error
+ InjectOutbound(dest tcpip.Address, packet []byte) tcpip.Error
}
-// A LinkAddressResolver is an extension to a NetworkProtocol that
-// can resolve link addresses.
+// A LinkAddressResolver handles link address resolution for a network protocol.
type LinkAddressResolver interface {
// LinkAddressRequest sends a request for the link address of the target
// address. The request is broadcasted on the local network if a remote link
// address is not provided.
- //
- // The request is sent from the passed network interface. If the interface
- // local address is unspecified, any interface local address may be used.
- LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, nic NetworkInterface) *tcpip.Error
+ LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) tcpip.Error
// ResolveStaticAddress attempts to resolve address without sending
// requests. It either resolves the name immediately or returns the
@@ -847,22 +859,16 @@ type LinkAddressResolver interface {
LinkAddressProtocol() tcpip.NetworkProtocolNumber
}
-// A LinkAddressCache caches link addresses.
-type LinkAddressCache interface {
- // AddLinkAddress adds a link address to the cache.
- AddLinkAddress(addr tcpip.Address, linkAddr tcpip.LinkAddress)
-}
-
// RawFactory produces endpoints for writing various types of raw packets.
type RawFactory interface {
// NewUnassociatedEndpoint produces endpoints for writing packets not
// associated with a particular transport protocol. Such endpoints can
// be used to write arbitrary packets that include the network header.
- NewUnassociatedEndpoint(stack *Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error)
+ NewUnassociatedEndpoint(stack *Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error)
// NewPacketEndpoint produces endpoints for reading and writing packets
// that include network and (when cooked is false) link layer headers.
- NewPacketEndpoint(stack *Stack, cooked bool, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error)
+ NewPacketEndpoint(stack *Stack, cooked bool, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error)
}
// GSOType is the type of GSO segments.
diff --git a/pkg/tcpip/stack/route.go b/pkg/tcpip/stack/route.go
index d9a8554e2..bab55ce49 100644
--- a/pkg/tcpip/stack/route.go
+++ b/pkg/tcpip/stack/route.go
@@ -53,7 +53,7 @@ type Route struct {
// linkRes is set if link address resolution is enabled for this protocol on
// the route's NIC.
- linkRes LinkAddressResolver
+ linkRes linkResolver
}
type routeInfo struct {
@@ -174,7 +174,7 @@ func makeRoute(netProto tcpip.NetworkProtocolNumber, gateway, localAddr, remoteA
}
if r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilityResolutionRequired != 0 {
- if linkRes, ok := r.outgoingNIC.stack.linkAddrResolvers[r.NetProto]; ok {
+ if linkRes, ok := r.outgoingNIC.linkAddrResolvers[r.NetProto]; ok {
r.linkRes = linkRes
}
}
@@ -184,11 +184,11 @@ func makeRoute(netProto tcpip.NetworkProtocolNumber, gateway, localAddr, remoteA
return r
}
- if r.linkRes == nil {
+ if r.linkRes.resolver == nil {
return r
}
- if linkAddr, ok := r.linkRes.ResolveStaticAddress(r.RemoteAddress); ok {
+ if linkAddr, ok := r.linkRes.resolver.ResolveStaticAddress(r.RemoteAddress); ok {
r.ResolveWith(linkAddr)
return r
}
@@ -331,7 +331,7 @@ type ResolvedFieldsResult struct {
//
// Note, the route will not cache the remote link address when address
// resolution completes.
-func (r *Route) ResolvedFields(afterResolve func(ResolvedFieldsResult)) *tcpip.Error {
+func (r *Route) ResolvedFields(afterResolve func(ResolvedFieldsResult)) tcpip.Error {
_, _, err := r.resolvedFields(afterResolve)
return err
}
@@ -342,7 +342,7 @@ func (r *Route) ResolvedFields(afterResolve func(ResolvedFieldsResult)) *tcpip.E
//
// The route's fields will also be returned, regardless of whether address
// resolution is required or not.
-func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteInfo, <-chan struct{}, *tcpip.Error) {
+func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteInfo, <-chan struct{}, tcpip.Error) {
r.mu.RLock()
fields := r.fieldsLocked()
resolutionRequired := r.isResolutionRequiredRLocked()
@@ -354,11 +354,6 @@ func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteIn
return fields, nil, nil
}
- nextAddr := r.NextHop
- if nextAddr == "" {
- nextAddr = r.RemoteAddress
- }
-
// If specified, the local address used for link address resolution must be an
// address on the outgoing interface.
var linkAddressResolutionRequestLocalAddr tcpip.Address
@@ -367,7 +362,7 @@ func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteIn
}
afterResolveFields := fields
- linkAddr, ch, err := r.outgoingNIC.getNeighborLinkAddress(nextAddr, linkAddressResolutionRequestLocalAddr, r.linkRes, func(r LinkResolutionResult) {
+ linkAddr, ch, err := r.linkRes.getNeighborLinkAddress(r.nextHop(), linkAddressResolutionRequestLocalAddr, func(r LinkResolutionResult) {
if afterResolve != nil {
if r.Success {
afterResolveFields.RemoteLinkAddress = r.LinkAddress
@@ -382,6 +377,13 @@ func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteIn
return fields, ch, err
}
+func (r *Route) nextHop() tcpip.Address {
+ if len(r.NextHop) == 0 {
+ return r.RemoteAddress
+ }
+ return r.NextHop
+}
+
// local returns true if the route is a local route.
func (r *Route) local() bool {
return r.Loop == PacketLoop || r.outgoingNIC.IsLoopback()
@@ -398,7 +400,7 @@ func (r *Route) IsResolutionRequired() bool {
}
func (r *Route) isResolutionRequiredRLocked() bool {
- return len(r.mu.remoteLinkAddress) == 0 && r.linkRes != nil && r.isValidForOutgoingRLocked() && !r.local()
+ return len(r.mu.remoteLinkAddress) == 0 && r.linkRes.resolver != nil && r.isValidForOutgoingRLocked() && !r.local()
}
func (r *Route) isValidForOutgoing() bool {
@@ -427,9 +429,9 @@ func (r *Route) isValidForOutgoingRLocked() bool {
}
// WritePacket writes the packet through the given route.
-func (r *Route) WritePacket(gso *GSO, params NetworkHeaderParams, pkt *PacketBuffer) *tcpip.Error {
+func (r *Route) WritePacket(gso *GSO, params NetworkHeaderParams, pkt *PacketBuffer) tcpip.Error {
if !r.isValidForOutgoing() {
- return tcpip.ErrInvalidEndpointState
+ return &tcpip.ErrInvalidEndpointState{}
}
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).WritePacket(r, gso, params, pkt)
@@ -437,9 +439,9 @@ func (r *Route) WritePacket(gso *GSO, params NetworkHeaderParams, pkt *PacketBuf
// WritePackets writes a list of n packets through the given route and returns
// the number of packets written.
-func (r *Route) WritePackets(gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, *tcpip.Error) {
+func (r *Route) WritePackets(gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, tcpip.Error) {
if !r.isValidForOutgoing() {
- return 0, tcpip.ErrInvalidEndpointState
+ return 0, &tcpip.ErrInvalidEndpointState{}
}
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).WritePackets(r, gso, pkts, params)
@@ -447,9 +449,9 @@ func (r *Route) WritePackets(gso *GSO, pkts PacketBufferList, params NetworkHead
// WriteHeaderIncludedPacket writes a packet already containing a network
// header through the given route.
-func (r *Route) WriteHeaderIncludedPacket(pkt *PacketBuffer) *tcpip.Error {
+func (r *Route) WriteHeaderIncludedPacket(pkt *PacketBuffer) tcpip.Error {
if !r.isValidForOutgoing() {
- return tcpip.ErrInvalidEndpointState
+ return &tcpip.ErrInvalidEndpointState{}
}
return r.outgoingNIC.getNetworkEndpoint(r.NetProto).WriteHeaderIncludedPacket(r, pkt)
@@ -519,3 +521,14 @@ func (r *Route) IsOutboundBroadcast() bool {
// Only IPv4 has a notion of broadcast.
return r.isV4Broadcast(r.RemoteAddress)
}
+
+// ConfirmReachable informs the network/link layer that the neighbour used for
+// the route is reachable.
+//
+// "Reachable" is defined as having full-duplex communication between the
+// local and remote ends of the route.
+func (r *Route) ConfirmReachable() {
+ if r.linkRes.resolver != nil {
+ r.linkRes.confirmReachable(r.nextHop())
+ }
+}
diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go
index e9c5db4c3..a51d758d0 100644
--- a/pkg/tcpip/stack/stack.go
+++ b/pkg/tcpip/stack/stack.go
@@ -76,12 +76,16 @@ type TCPCubicState struct {
// TCPRACKState is used to hold a copy of the internal RACK state when the
// TCPProbeFunc is invoked.
type TCPRACKState struct {
- XmitTime time.Time
- EndSequence seqnum.Value
- FACK seqnum.Value
- RTT time.Duration
- Reord bool
- DSACKSeen bool
+ XmitTime time.Time
+ EndSequence seqnum.Value
+ FACK seqnum.Value
+ RTT time.Duration
+ Reord bool
+ DSACKSeen bool
+ ReoWnd time.Duration
+ ReoWndIncr uint8
+ ReoWndPersist int8
+ RTTSeq seqnum.Value
}
// TCPEndpointID is the unique 4 tuple that identifies a given endpoint.
@@ -372,7 +376,6 @@ func (u *uniqueIDGenerator) UniqueID() uint64 {
type Stack struct {
transportProtocols map[tcpip.TransportProtocolNumber]*transportProtocolState
networkProtocols map[tcpip.NetworkProtocolNumber]NetworkProtocol
- linkAddrResolvers map[tcpip.NetworkProtocolNumber]LinkAddressResolver
// rawFactory creates raw endpoints. If nil, raw endpoints are
// disabled. It is set during Stack creation and is immutable.
@@ -382,6 +385,15 @@ type Stack struct {
stats tcpip.Stats
+ // LOCK ORDERING: mu > route.mu.
+ route struct {
+ mu struct {
+ sync.RWMutex
+
+ table []tcpip.Route
+ }
+ }
+
mu sync.RWMutex
nics map[tcpip.NICID]*NIC
@@ -389,11 +401,6 @@ type Stack struct {
cleanupEndpointsMu sync.Mutex
cleanupEndpoints map[TransportEndpoint]struct{}
- // route is the route table passed in by the user via SetRouteTable(),
- // it is used by FindRoute() to build a route for a specific
- // destination.
- routeTable []tcpip.Route
-
*ports.PortManager
// If not nil, then any new endpoints will have this probe function
@@ -429,6 +436,8 @@ type Stack struct {
// useNeighborCache indicates whether ARP and NDP packets should be handled
// by the NIC's neighborCache instead of linkAddrCache.
+ //
+ // TODO(gvisor.dev/issue/4658): Remove this field.
useNeighborCache bool
// nudDisp is the NUD event dispatcher that is used to send the netstack
@@ -449,6 +458,18 @@ type Stack struct {
// receiveBufferSize holds the min/default/max receive buffer sizes for
// endpoints other than TCP.
receiveBufferSize ReceiveBufferSizeOption
+
+ // tcpInvalidRateLimit is the maximal rate for sending duplicate
+ // acknowledgements in response to incoming TCP packets that are for an existing
+ // connection but that are invalid due to any of the following reasons:
+ //
+ // a) out-of-window sequence number.
+ // b) out-of-window acknowledgement number.
+ // c) PAWS check failure (when implemented).
+ //
+ // This is required to prevent potential ACK loops.
+ // Setting this to 0 will disable all rate limiting.
+ tcpInvalidRateLimit time.Duration
}
// UniqueID is an abstract generator of unique identifiers.
@@ -495,13 +516,17 @@ type Options struct {
// NUDConfigs is the default NUD configurations used by interfaces.
NUDConfigs NUDConfigurations
- // UseNeighborCache indicates whether ARP and NDP packets should be handled
- // by the Neighbor Unreachability Detection (NUD) state machine. This flag
- // also enables the APIs for inspecting and modifying the neighbor table via
- // NUDDispatcher and the following Stack methods: Neighbors, RemoveNeighbor,
- // and ClearNeighbors.
+ // UseNeighborCache is unused.
+ //
+ // TODO(gvisor.dev/issue/4658): Remove this field.
UseNeighborCache bool
+ // UseLinkAddrCache indicates that the legacy link address cache should be
+ // used for link resolution.
+ //
+ // TODO(gvisor.dev/issue/4658): Remove this field.
+ UseLinkAddrCache bool
+
// NUDDisp is the NUD event dispatcher that an integrator can provide to
// receive NUD related events.
NUDDisp NUDDispatcher
@@ -552,7 +577,7 @@ type TransportEndpointInfo struct {
// incompatible with the receiver.
//
// Preconditon: the parent endpoint mu must be held while calling this method.
-func (t *TransportEndpointInfo) AddrNetProtoLocked(addr tcpip.FullAddress, v6only bool) (tcpip.FullAddress, tcpip.NetworkProtocolNumber, *tcpip.Error) {
+func (t *TransportEndpointInfo) AddrNetProtoLocked(addr tcpip.FullAddress, v6only bool) (tcpip.FullAddress, tcpip.NetworkProtocolNumber, tcpip.Error) {
netProto := t.NetProto
switch len(addr.Addr) {
case header.IPv4AddressSize:
@@ -570,11 +595,11 @@ func (t *TransportEndpointInfo) AddrNetProtoLocked(addr tcpip.FullAddress, v6onl
switch len(t.ID.LocalAddress) {
case header.IPv4AddressSize:
if len(addr.Addr) == header.IPv6AddressSize {
- return tcpip.FullAddress{}, 0, tcpip.ErrInvalidEndpointState
+ return tcpip.FullAddress{}, 0, &tcpip.ErrInvalidEndpointState{}
}
case header.IPv6AddressSize:
if len(addr.Addr) == header.IPv4AddressSize {
- return tcpip.FullAddress{}, 0, tcpip.ErrNetworkUnreachable
+ return tcpip.FullAddress{}, 0, &tcpip.ErrNetworkUnreachable{}
}
}
@@ -582,10 +607,10 @@ func (t *TransportEndpointInfo) AddrNetProtoLocked(addr tcpip.FullAddress, v6onl
case netProto == t.NetProto:
case netProto == header.IPv4ProtocolNumber && t.NetProto == header.IPv6ProtocolNumber:
if v6only {
- return tcpip.FullAddress{}, 0, tcpip.ErrNoRoute
+ return tcpip.FullAddress{}, 0, &tcpip.ErrNoRoute{}
}
default:
- return tcpip.FullAddress{}, 0, tcpip.ErrInvalidEndpointState
+ return tcpip.FullAddress{}, 0, &tcpip.ErrInvalidEndpointState{}
}
return addr, netProto, nil
@@ -631,7 +656,6 @@ func New(opts Options) *Stack {
s := &Stack{
transportProtocols: make(map[tcpip.TransportProtocolNumber]*transportProtocolState),
networkProtocols: make(map[tcpip.NetworkProtocolNumber]NetworkProtocol),
- linkAddrResolvers: make(map[tcpip.NetworkProtocolNumber]LinkAddressResolver),
nics: make(map[tcpip.NICID]*NIC),
cleanupEndpoints: make(map[TransportEndpoint]struct{}),
PortManager: ports.NewPortManager(),
@@ -642,7 +666,7 @@ func New(opts Options) *Stack {
icmpRateLimiter: NewICMPRateLimiter(),
seed: generateRandUint32(),
nudConfigs: opts.NUDConfigs,
- useNeighborCache: opts.UseNeighborCache,
+ useNeighborCache: !opts.UseLinkAddrCache,
uniqueIDGenerator: opts.UniqueID,
nudDisp: opts.NUDDisp,
randomGenerator: mathrand.New(randSrc),
@@ -656,15 +680,13 @@ func New(opts Options) *Stack {
Default: DefaultBufferSize,
Max: DefaultMaxBufferSize,
},
+ tcpInvalidRateLimit: defaultTCPInvalidRateLimit,
}
// Add specified network protocols.
for _, netProtoFactory := range opts.NetworkProtocols {
netProto := netProtoFactory(s)
s.networkProtocols[netProto.Number()] = netProto
- if r, ok := netProto.(LinkAddressResolver); ok {
- s.linkAddrResolvers[r.LinkAddressProtocol()] = r
- }
}
// Add specified transport protocols.
@@ -698,10 +720,10 @@ func (s *Stack) UniqueID() uint64 {
// options. This method returns an error if the protocol is not supported or
// option is not supported by the protocol implementation or the provided value
// is incorrect.
-func (s *Stack) SetNetworkProtocolOption(network tcpip.NetworkProtocolNumber, option tcpip.SettableNetworkProtocolOption) *tcpip.Error {
+func (s *Stack) SetNetworkProtocolOption(network tcpip.NetworkProtocolNumber, option tcpip.SettableNetworkProtocolOption) tcpip.Error {
netProto, ok := s.networkProtocols[network]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
return netProto.SetOption(option)
}
@@ -715,10 +737,10 @@ func (s *Stack) SetNetworkProtocolOption(network tcpip.NetworkProtocolNumber, op
// if err != nil {
// ...
// }
-func (s *Stack) NetworkProtocolOption(network tcpip.NetworkProtocolNumber, option tcpip.GettableNetworkProtocolOption) *tcpip.Error {
+func (s *Stack) NetworkProtocolOption(network tcpip.NetworkProtocolNumber, option tcpip.GettableNetworkProtocolOption) tcpip.Error {
netProto, ok := s.networkProtocols[network]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
return netProto.Option(option)
}
@@ -727,10 +749,10 @@ func (s *Stack) NetworkProtocolOption(network tcpip.NetworkProtocolNumber, optio
// options. This method returns an error if the protocol is not supported or
// option is not supported by the protocol implementation or the provided value
// is incorrect.
-func (s *Stack) SetTransportProtocolOption(transport tcpip.TransportProtocolNumber, option tcpip.SettableTransportProtocolOption) *tcpip.Error {
+func (s *Stack) SetTransportProtocolOption(transport tcpip.TransportProtocolNumber, option tcpip.SettableTransportProtocolOption) tcpip.Error {
transProtoState, ok := s.transportProtocols[transport]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
return transProtoState.proto.SetOption(option)
}
@@ -742,10 +764,10 @@ func (s *Stack) SetTransportProtocolOption(transport tcpip.TransportProtocolNumb
// if err := s.TransportProtocolOption(tcpip.TCPProtocolNumber, &v); err != nil {
// ...
// }
-func (s *Stack) TransportProtocolOption(transport tcpip.TransportProtocolNumber, option tcpip.GettableTransportProtocolOption) *tcpip.Error {
+func (s *Stack) TransportProtocolOption(transport tcpip.TransportProtocolNumber, option tcpip.GettableTransportProtocolOption) tcpip.Error {
transProtoState, ok := s.transportProtocols[transport]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
return transProtoState.proto.Option(option)
}
@@ -778,15 +800,15 @@ func (s *Stack) Stats() tcpip.Stats {
// SetForwarding enables or disables packet forwarding between NICs for the
// passed protocol.
-func (s *Stack) SetForwarding(protocolNum tcpip.NetworkProtocolNumber, enable bool) *tcpip.Error {
+func (s *Stack) SetForwarding(protocolNum tcpip.NetworkProtocolNumber, enable bool) tcpip.Error {
protocol, ok := s.networkProtocols[protocolNum]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
forwardingProtocol, ok := protocol.(ForwardingNetworkProtocol)
if !ok {
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
forwardingProtocol.SetForwarding(enable)
@@ -814,45 +836,44 @@ func (s *Stack) Forwarding(protocolNum tcpip.NetworkProtocolNumber) bool {
//
// This method takes ownership of the table.
func (s *Stack) SetRouteTable(table []tcpip.Route) {
- s.mu.Lock()
- defer s.mu.Unlock()
-
- s.routeTable = table
+ s.route.mu.Lock()
+ defer s.route.mu.Unlock()
+ s.route.mu.table = table
}
// GetRouteTable returns the route table which is currently in use.
func (s *Stack) GetRouteTable() []tcpip.Route {
- s.mu.Lock()
- defer s.mu.Unlock()
- return append([]tcpip.Route(nil), s.routeTable...)
+ s.route.mu.RLock()
+ defer s.route.mu.RUnlock()
+ return append([]tcpip.Route(nil), s.route.mu.table...)
}
// AddRoute appends a route to the route table.
func (s *Stack) AddRoute(route tcpip.Route) {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.routeTable = append(s.routeTable, route)
+ s.route.mu.Lock()
+ defer s.route.mu.Unlock()
+ s.route.mu.table = append(s.route.mu.table, route)
}
// RemoveRoutes removes matching routes from the route table.
func (s *Stack) RemoveRoutes(match func(tcpip.Route) bool) {
- s.mu.Lock()
- defer s.mu.Unlock()
+ s.route.mu.Lock()
+ defer s.route.mu.Unlock()
var filteredRoutes []tcpip.Route
- for _, route := range s.routeTable {
+ for _, route := range s.route.mu.table {
if !match(route) {
filteredRoutes = append(filteredRoutes, route)
}
}
- s.routeTable = filteredRoutes
+ s.route.mu.table = filteredRoutes
}
// NewEndpoint creates a new transport layer endpoint of the given protocol.
-func (s *Stack) NewEndpoint(transport tcpip.TransportProtocolNumber, network tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
+func (s *Stack) NewEndpoint(transport tcpip.TransportProtocolNumber, network tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
t, ok := s.transportProtocols[transport]
if !ok {
- return nil, tcpip.ErrUnknownProtocol
+ return nil, &tcpip.ErrUnknownProtocol{}
}
return t.proto.NewEndpoint(network, waiterQueue)
@@ -861,9 +882,9 @@ func (s *Stack) NewEndpoint(transport tcpip.TransportProtocolNumber, network tcp
// NewRawEndpoint creates a new raw transport layer endpoint of the given
// protocol. Raw endpoints receive all traffic for a given protocol regardless
// of address.
-func (s *Stack) NewRawEndpoint(transport tcpip.TransportProtocolNumber, network tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue, associated bool) (tcpip.Endpoint, *tcpip.Error) {
+func (s *Stack) NewRawEndpoint(transport tcpip.TransportProtocolNumber, network tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue, associated bool) (tcpip.Endpoint, tcpip.Error) {
if s.rawFactory == nil {
- return nil, tcpip.ErrNotPermitted
+ return nil, &tcpip.ErrNotPermitted{}
}
if !associated {
@@ -872,7 +893,7 @@ func (s *Stack) NewRawEndpoint(transport tcpip.TransportProtocolNumber, network
t, ok := s.transportProtocols[transport]
if !ok {
- return nil, tcpip.ErrUnknownProtocol
+ return nil, &tcpip.ErrUnknownProtocol{}
}
return t.proto.NewRawEndpoint(network, waiterQueue)
@@ -880,9 +901,9 @@ func (s *Stack) NewRawEndpoint(transport tcpip.TransportProtocolNumber, network
// NewPacketEndpoint creates a new packet endpoint listening for the given
// netProto.
-func (s *Stack) NewPacketEndpoint(cooked bool, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
+func (s *Stack) NewPacketEndpoint(cooked bool, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
if s.rawFactory == nil {
- return nil, tcpip.ErrNotPermitted
+ return nil, &tcpip.ErrNotPermitted{}
}
return s.rawFactory.NewPacketEndpoint(s, cooked, netProto, waiterQueue)
@@ -913,20 +934,20 @@ type NICOptions struct {
// NICs can be configured.
//
// LinkEndpoint.Attach will be called to bind ep with a NetworkDispatcher.
-func (s *Stack) CreateNICWithOptions(id tcpip.NICID, ep LinkEndpoint, opts NICOptions) *tcpip.Error {
+func (s *Stack) CreateNICWithOptions(id tcpip.NICID, ep LinkEndpoint, opts NICOptions) tcpip.Error {
s.mu.Lock()
defer s.mu.Unlock()
// Make sure id is unique.
if _, ok := s.nics[id]; ok {
- return tcpip.ErrDuplicateNICID
+ return &tcpip.ErrDuplicateNICID{}
}
// Make sure name is unique, unless unnamed.
if opts.Name != "" {
for _, n := range s.nics {
if n.Name() == opts.Name {
- return tcpip.ErrDuplicateNICID
+ return &tcpip.ErrDuplicateNICID{}
}
}
}
@@ -942,7 +963,7 @@ func (s *Stack) CreateNICWithOptions(id tcpip.NICID, ep LinkEndpoint, opts NICOp
// CreateNIC creates a NIC with the provided id and LinkEndpoint and calls
// LinkEndpoint.Attach to bind ep with a NetworkDispatcher.
-func (s *Stack) CreateNIC(id tcpip.NICID, ep LinkEndpoint) *tcpip.Error {
+func (s *Stack) CreateNIC(id tcpip.NICID, ep LinkEndpoint) tcpip.Error {
return s.CreateNICWithOptions(id, ep, NICOptions{})
}
@@ -960,26 +981,26 @@ func (s *Stack) GetLinkEndpointByName(name string) LinkEndpoint {
// EnableNIC enables the given NIC so that the link-layer endpoint can start
// delivering packets to it.
-func (s *Stack) EnableNIC(id tcpip.NICID) *tcpip.Error {
+func (s *Stack) EnableNIC(id tcpip.NICID) tcpip.Error {
s.mu.RLock()
defer s.mu.RUnlock()
nic, ok := s.nics[id]
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
return nic.enable()
}
// DisableNIC disables the given NIC.
-func (s *Stack) DisableNIC(id tcpip.NICID) *tcpip.Error {
+func (s *Stack) DisableNIC(id tcpip.NICID) tcpip.Error {
s.mu.RLock()
defer s.mu.RUnlock()
nic, ok := s.nics[id]
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
nic.disable()
@@ -1000,7 +1021,7 @@ func (s *Stack) CheckNIC(id tcpip.NICID) bool {
}
// RemoveNIC removes NIC and all related routes from the network stack.
-func (s *Stack) RemoveNIC(id tcpip.NICID) *tcpip.Error {
+func (s *Stack) RemoveNIC(id tcpip.NICID) tcpip.Error {
s.mu.Lock()
defer s.mu.Unlock()
@@ -1010,25 +1031,26 @@ func (s *Stack) RemoveNIC(id tcpip.NICID) *tcpip.Error {
// removeNICLocked removes NIC and all related routes from the network stack.
//
// s.mu must be locked.
-func (s *Stack) removeNICLocked(id tcpip.NICID) *tcpip.Error {
+func (s *Stack) removeNICLocked(id tcpip.NICID) tcpip.Error {
nic, ok := s.nics[id]
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
delete(s.nics, id)
// Remove routes in-place. n tracks the number of routes written.
+ s.route.mu.Lock()
n := 0
- for i, r := range s.routeTable {
- s.routeTable[i] = tcpip.Route{}
+ for i, r := range s.route.mu.table {
+ s.route.mu.table[i] = tcpip.Route{}
if r.NIC != id {
// Keep this route.
- s.routeTable[n] = r
+ s.route.mu.table[n] = r
n++
}
}
-
- s.routeTable = s.routeTable[:n]
+ s.route.mu.table = s.route.mu.table[:n]
+ s.route.mu.Unlock()
return nic.remove()
}
@@ -1118,13 +1140,13 @@ type NICStateFlags struct {
}
// AddAddress adds a new network-layer address to the specified NIC.
-func (s *Stack) AddAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) *tcpip.Error {
+func (s *Stack) AddAddress(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error {
return s.AddAddressWithOptions(id, protocol, addr, CanBePrimaryEndpoint)
}
// AddAddressWithPrefix is the same as AddAddress, but allows you to specify
// the address prefix.
-func (s *Stack) AddAddressWithPrefix(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.AddressWithPrefix) *tcpip.Error {
+func (s *Stack) AddAddressWithPrefix(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.AddressWithPrefix) tcpip.Error {
ap := tcpip.ProtocolAddress{
Protocol: protocol,
AddressWithPrefix: addr,
@@ -1134,16 +1156,16 @@ func (s *Stack) AddAddressWithPrefix(id tcpip.NICID, protocol tcpip.NetworkProto
// AddProtocolAddress adds a new network-layer protocol address to the
// specified NIC.
-func (s *Stack) AddProtocolAddress(id tcpip.NICID, protocolAddress tcpip.ProtocolAddress) *tcpip.Error {
+func (s *Stack) AddProtocolAddress(id tcpip.NICID, protocolAddress tcpip.ProtocolAddress) tcpip.Error {
return s.AddProtocolAddressWithOptions(id, protocolAddress, CanBePrimaryEndpoint)
}
// AddAddressWithOptions is the same as AddAddress, but allows you to specify
// whether the new endpoint can be primary or not.
-func (s *Stack) AddAddressWithOptions(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, peb PrimaryEndpointBehavior) *tcpip.Error {
+func (s *Stack) AddAddressWithOptions(id tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, peb PrimaryEndpointBehavior) tcpip.Error {
netProto, ok := s.networkProtocols[protocol]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
return s.AddProtocolAddressWithOptions(id, tcpip.ProtocolAddress{
Protocol: protocol,
@@ -1156,13 +1178,13 @@ func (s *Stack) AddAddressWithOptions(id tcpip.NICID, protocol tcpip.NetworkProt
// AddProtocolAddressWithOptions is the same as AddProtocolAddress, but allows
// you to specify whether the new endpoint can be primary or not.
-func (s *Stack) AddProtocolAddressWithOptions(id tcpip.NICID, protocolAddress tcpip.ProtocolAddress, peb PrimaryEndpointBehavior) *tcpip.Error {
+func (s *Stack) AddProtocolAddressWithOptions(id tcpip.NICID, protocolAddress tcpip.ProtocolAddress, peb PrimaryEndpointBehavior) tcpip.Error {
s.mu.RLock()
defer s.mu.RUnlock()
nic, ok := s.nics[id]
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
return nic.addAddress(protocolAddress, peb)
@@ -1170,7 +1192,7 @@ func (s *Stack) AddProtocolAddressWithOptions(id tcpip.NICID, protocolAddress tc
// RemoveAddress removes an existing network-layer address from the specified
// NIC.
-func (s *Stack) RemoveAddress(id tcpip.NICID, addr tcpip.Address) *tcpip.Error {
+func (s *Stack) RemoveAddress(id tcpip.NICID, addr tcpip.Address) tcpip.Error {
s.mu.RLock()
defer s.mu.RUnlock()
@@ -1178,7 +1200,7 @@ func (s *Stack) RemoveAddress(id tcpip.NICID, addr tcpip.Address) *tcpip.Error {
return nic.removeAddress(addr)
}
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
// AllAddresses returns a map of NICIDs to their protocol addresses (primary
@@ -1308,7 +1330,7 @@ func (s *Stack) findLocalRouteRLocked(localAddressNICID tcpip.NICID, localAddr,
// If no local address is provided, the stack will select a local address. If no
// remote address is provided, the stack wil use a remote address equal to the
// local address.
-func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber, multicastLoop bool) (*Route, *tcpip.Error) {
+func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, netProto tcpip.NetworkProtocolNumber, multicastLoop bool) (*Route, tcpip.Error) {
s.mu.RLock()
defer s.mu.RUnlock()
@@ -1344,48 +1366,58 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
}
if isLoopback {
- return nil, tcpip.ErrBadLocalAddress
+ return nil, &tcpip.ErrBadLocalAddress{}
}
- return nil, tcpip.ErrNetworkUnreachable
+ return nil, &tcpip.ErrNetworkUnreachable{}
}
canForward := s.Forwarding(netProto) && !header.IsV6LinkLocalAddress(localAddr) && !isLinkLocal
// Find a route to the remote with the route table.
var chosenRoute tcpip.Route
- for _, route := range s.routeTable {
- if len(remoteAddr) != 0 && !route.Destination.Contains(remoteAddr) {
- continue
- }
+ if r := func() *Route {
+ s.route.mu.RLock()
+ defer s.route.mu.RUnlock()
- nic, ok := s.nics[route.NIC]
- if !ok || !nic.Enabled() {
- continue
- }
+ for _, route := range s.route.mu.table {
+ if len(remoteAddr) != 0 && !route.Destination.Contains(remoteAddr) {
+ continue
+ }
- if id == 0 || id == route.NIC {
- if addressEndpoint := s.getAddressEP(nic, localAddr, remoteAddr, netProto); addressEndpoint != nil {
- var gateway tcpip.Address
- if needRoute {
- gateway = route.Gateway
- }
- r := constructAndValidateRoute(netProto, addressEndpoint, nic /* outgoingNIC */, nic /* outgoingNIC */, gateway, localAddr, remoteAddr, s.handleLocal, multicastLoop)
- if r == nil {
- panic(fmt.Sprintf("non-forwarding route validation failed with route table entry = %#v, id = %d, localAddr = %s, remoteAddr = %s", route, id, localAddr, remoteAddr))
+ nic, ok := s.nics[route.NIC]
+ if !ok || !nic.Enabled() {
+ continue
+ }
+
+ if id == 0 || id == route.NIC {
+ if addressEndpoint := s.getAddressEP(nic, localAddr, remoteAddr, netProto); addressEndpoint != nil {
+ var gateway tcpip.Address
+ if needRoute {
+ gateway = route.Gateway
+ }
+ r := constructAndValidateRoute(netProto, addressEndpoint, nic /* outgoingNIC */, nic /* outgoingNIC */, gateway, localAddr, remoteAddr, s.handleLocal, multicastLoop)
+ if r == nil {
+ panic(fmt.Sprintf("non-forwarding route validation failed with route table entry = %#v, id = %d, localAddr = %s, remoteAddr = %s", route, id, localAddr, remoteAddr))
+ }
+ return r
}
- return r, nil
}
- }
- // If the stack has forwarding enabled and we haven't found a valid route to
- // the remote address yet, keep track of the first valid route. We keep
- // iterating because we prefer routes that let us use a local address that
- // is assigned to the outgoing interface. There is no requirement to do this
- // from any RFC but simply a choice made to better follow a strong host
- // model which the netstack follows at the time of writing.
- if canForward && chosenRoute == (tcpip.Route{}) {
- chosenRoute = route
+ // If the stack has forwarding enabled and we haven't found a valid route
+ // to the remote address yet, keep track of the first valid route. We
+ // keep iterating because we prefer routes that let us use a local
+ // address that is assigned to the outgoing interface. There is no
+ // requirement to do this from any RFC but simply a choice made to better
+ // follow a strong host model which the netstack follows at the time of
+ // writing.
+ if canForward && chosenRoute == (tcpip.Route{}) {
+ chosenRoute = route
+ }
}
+
+ return nil
+ }(); r != nil {
+ return r, nil
}
if chosenRoute != (tcpip.Route{}) {
@@ -1412,7 +1444,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
}
}
- return nil, tcpip.ErrNoRoute
+ return nil, &tcpip.ErrNoRoute{}
}
if id == 0 {
@@ -1432,12 +1464,12 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
}
if needRoute {
- return nil, tcpip.ErrNoRoute
+ return nil, &tcpip.ErrNoRoute{}
}
if header.IsV6LoopbackAddress(remoteAddr) {
- return nil, tcpip.ErrBadLocalAddress
+ return nil, &tcpip.ErrBadLocalAddress{}
}
- return nil, tcpip.ErrNetworkUnreachable
+ return nil, &tcpip.ErrNetworkUnreachable{}
}
// CheckNetworkProtocol checks if a given network protocol is enabled in the
@@ -1483,13 +1515,13 @@ func (s *Stack) CheckLocalAddress(nicID tcpip.NICID, protocol tcpip.NetworkProto
}
// SetPromiscuousMode enables or disables promiscuous mode in the given NIC.
-func (s *Stack) SetPromiscuousMode(nicID tcpip.NICID, enable bool) *tcpip.Error {
+func (s *Stack) SetPromiscuousMode(nicID tcpip.NICID, enable bool) tcpip.Error {
s.mu.RLock()
defer s.mu.RUnlock()
nic, ok := s.nics[nicID]
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
nic.setPromiscuousMode(enable)
@@ -1499,13 +1531,13 @@ func (s *Stack) SetPromiscuousMode(nicID tcpip.NICID, enable bool) *tcpip.Error
// SetSpoofing enables or disables address spoofing in the given NIC, allowing
// endpoints to bind to any address in the NIC.
-func (s *Stack) SetSpoofing(nicID tcpip.NICID, enable bool) *tcpip.Error {
+func (s *Stack) SetSpoofing(nicID tcpip.NICID, enable bool) tcpip.Error {
s.mu.RLock()
defer s.mu.RUnlock()
nic, ok := s.nics[nicID]
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
nic.setSpoofing(enable)
@@ -1513,20 +1545,6 @@ func (s *Stack) SetSpoofing(nicID tcpip.NICID, enable bool) *tcpip.Error {
return nil
}
-// AddLinkAddress adds a link address for the neighbor on the specified NIC.
-func (s *Stack) AddLinkAddress(nicID tcpip.NICID, neighbor tcpip.Address, linkAddr tcpip.LinkAddress) *tcpip.Error {
- s.mu.RLock()
- defer s.mu.RUnlock()
-
- nic, ok := s.nics[nicID]
- if !ok {
- return tcpip.ErrUnknownNICID
- }
-
- nic.linkAddrCache.AddLinkAddress(neighbor, linkAddr)
- return nil
-}
-
// LinkResolutionResult is the result of a link address resolution attempt.
type LinkResolutionResult struct {
LinkAddress tcpip.LinkAddress
@@ -1549,93 +1567,82 @@ type LinkResolutionResult struct {
// If specified, the local address must be an address local to the interface
// the neighbor cache belongs to. The local address is the source address of
// a packet prompting NUD/link address resolution.
-func (s *Stack) GetLinkAddress(nicID tcpip.NICID, addr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, onResolve func(LinkResolutionResult)) *tcpip.Error {
+func (s *Stack) GetLinkAddress(nicID tcpip.NICID, addr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, onResolve func(LinkResolutionResult)) tcpip.Error {
s.mu.RLock()
nic, ok := s.nics[nicID]
s.mu.RUnlock()
if !ok {
- return tcpip.ErrUnknownNICID
- }
-
- linkRes, ok := s.linkAddrResolvers[protocol]
- if !ok {
- return tcpip.ErrNotSupported
- }
-
- if linkAddr, ok := linkRes.ResolveStaticAddress(addr); ok {
- onResolve(LinkResolutionResult{LinkAddress: linkAddr, Success: true})
- return nil
+ return &tcpip.ErrUnknownNICID{}
}
- _, _, err := nic.getNeighborLinkAddress(addr, localAddr, linkRes, onResolve)
- return err
+ return nic.getLinkAddress(addr, localAddr, protocol, onResolve)
}
// Neighbors returns all IP to MAC address associations.
-func (s *Stack) Neighbors(nicID tcpip.NICID) ([]NeighborEntry, *tcpip.Error) {
+func (s *Stack) Neighbors(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber) ([]NeighborEntry, tcpip.Error) {
s.mu.RLock()
nic, ok := s.nics[nicID]
s.mu.RUnlock()
if !ok {
- return nil, tcpip.ErrUnknownNICID
+ return nil, &tcpip.ErrUnknownNICID{}
}
- return nic.neighbors()
+ return nic.neighbors(protocol)
}
// AddStaticNeighbor statically associates an IP address to a MAC address.
-func (s *Stack) AddStaticNeighbor(nicID tcpip.NICID, addr tcpip.Address, linkAddr tcpip.LinkAddress) *tcpip.Error {
+func (s *Stack) AddStaticNeighbor(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address, linkAddr tcpip.LinkAddress) tcpip.Error {
s.mu.RLock()
nic, ok := s.nics[nicID]
s.mu.RUnlock()
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
- return nic.addStaticNeighbor(addr, linkAddr)
+ return nic.addStaticNeighbor(addr, protocol, linkAddr)
}
// RemoveNeighbor removes an IP to MAC address association previously created
// either automically or by AddStaticNeighbor. Returns ErrBadAddress if there
// is no association with the provided address.
-func (s *Stack) RemoveNeighbor(nicID tcpip.NICID, addr tcpip.Address) *tcpip.Error {
+func (s *Stack) RemoveNeighbor(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber, addr tcpip.Address) tcpip.Error {
s.mu.RLock()
nic, ok := s.nics[nicID]
s.mu.RUnlock()
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
- return nic.removeNeighbor(addr)
+ return nic.removeNeighbor(protocol, addr)
}
// ClearNeighbors removes all IP to MAC address associations.
-func (s *Stack) ClearNeighbors(nicID tcpip.NICID) *tcpip.Error {
+func (s *Stack) ClearNeighbors(nicID tcpip.NICID, protocol tcpip.NetworkProtocolNumber) tcpip.Error {
s.mu.RLock()
nic, ok := s.nics[nicID]
s.mu.RUnlock()
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
- return nic.clearNeighbors()
+ return nic.clearNeighbors(protocol)
}
// RegisterTransportEndpoint registers the given endpoint with the stack
// transport dispatcher. Received packets that match the provided id will be
// delivered to the given endpoint; specifying a nic is optional, but
// nic-specific IDs have precedence over global ones.
-func (s *Stack) RegisterTransportEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) *tcpip.Error {
+func (s *Stack) RegisterTransportEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
return s.demux.registerEndpoint(netProtos, protocol, id, ep, flags, bindToDevice)
}
// CheckRegisterTransportEndpoint checks if an endpoint can be registered with
// the stack transport dispatcher.
-func (s *Stack) CheckRegisterTransportEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, flags ports.Flags, bindToDevice tcpip.NICID) *tcpip.Error {
+func (s *Stack) CheckRegisterTransportEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
return s.demux.checkEndpoint(netProtos, protocol, id, flags, bindToDevice)
}
@@ -1672,7 +1679,7 @@ func (s *Stack) FindTransportEndpoint(netProto tcpip.NetworkProtocolNumber, tran
// RegisterRawTransportEndpoint registers the given endpoint with the stack
// transport dispatcher. Received packets that match the provided transport
// protocol will be delivered to the given endpoint.
-func (s *Stack) RegisterRawTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) *tcpip.Error {
+func (s *Stack) RegisterRawTransportEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) tcpip.Error {
return s.demux.registerRawEndpoint(netProto, transProto, ep)
}
@@ -1782,7 +1789,7 @@ func (s *Stack) Resume() {
// RegisterPacketEndpoint registers ep with the stack, causing it to receive
// all traffic of the specified netProto on the given NIC. If nicID is 0, it
// receives traffic from every NIC.
-func (s *Stack) RegisterPacketEndpoint(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) *tcpip.Error {
+func (s *Stack) RegisterPacketEndpoint(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, ep PacketEndpoint) tcpip.Error {
s.mu.Lock()
defer s.mu.Unlock()
@@ -1801,7 +1808,7 @@ func (s *Stack) RegisterPacketEndpoint(nicID tcpip.NICID, netProto tcpip.Network
// Capture on a specific device.
nic, ok := s.nics[nicID]
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
if err := nic.registerPacketEndpoint(netProto, ep); err != nil {
return err
@@ -1839,12 +1846,12 @@ func (s *Stack) unregisterPacketEndpointLocked(nicID tcpip.NICID, netProto tcpip
// WritePacketToRemote writes a payload on the specified NIC using the provided
// network protocol and remote link address.
-func (s *Stack) WritePacketToRemote(nicID tcpip.NICID, remote tcpip.LinkAddress, netProto tcpip.NetworkProtocolNumber, payload buffer.VectorisedView) *tcpip.Error {
+func (s *Stack) WritePacketToRemote(nicID tcpip.NICID, remote tcpip.LinkAddress, netProto tcpip.NetworkProtocolNumber, payload buffer.VectorisedView) tcpip.Error {
s.mu.Lock()
nic, ok := s.nics[nicID]
s.mu.Unlock()
if !ok {
- return tcpip.ErrUnknownDevice
+ return &tcpip.ErrUnknownDevice{}
}
pkt := NewPacketBuffer(PacketBufferOptions{
ReserveHeaderBytes: int(nic.MaxHeaderLength()),
@@ -1909,37 +1916,37 @@ func (s *Stack) RemoveTCPProbe() {
}
// JoinGroup joins the given multicast group on the given NIC.
-func (s *Stack) JoinGroup(protocol tcpip.NetworkProtocolNumber, nicID tcpip.NICID, multicastAddr tcpip.Address) *tcpip.Error {
+func (s *Stack) JoinGroup(protocol tcpip.NetworkProtocolNumber, nicID tcpip.NICID, multicastAddr tcpip.Address) tcpip.Error {
s.mu.RLock()
defer s.mu.RUnlock()
if nic, ok := s.nics[nicID]; ok {
return nic.joinGroup(protocol, multicastAddr)
}
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
// LeaveGroup leaves the given multicast group on the given NIC.
-func (s *Stack) LeaveGroup(protocol tcpip.NetworkProtocolNumber, nicID tcpip.NICID, multicastAddr tcpip.Address) *tcpip.Error {
+func (s *Stack) LeaveGroup(protocol tcpip.NetworkProtocolNumber, nicID tcpip.NICID, multicastAddr tcpip.Address) tcpip.Error {
s.mu.RLock()
defer s.mu.RUnlock()
if nic, ok := s.nics[nicID]; ok {
return nic.leaveGroup(protocol, multicastAddr)
}
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
// IsInGroup returns true if the NIC with ID nicID has joined the multicast
// group multicastAddr.
-func (s *Stack) IsInGroup(nicID tcpip.NICID, multicastAddr tcpip.Address) (bool, *tcpip.Error) {
+func (s *Stack) IsInGroup(nicID tcpip.NICID, multicastAddr tcpip.Address) (bool, tcpip.Error) {
s.mu.RLock()
defer s.mu.RUnlock()
if nic, ok := s.nics[nicID]; ok {
return nic.isInGroup(multicastAddr), nil
}
- return false, tcpip.ErrUnknownNICID
+ return false, &tcpip.ErrUnknownNICID{}
}
// IPTables returns the stack's iptables.
@@ -1979,45 +1986,45 @@ func (s *Stack) AllowICMPMessage() bool {
// GetNetworkEndpoint returns the NetworkEndpoint with the specified protocol
// number installed on the specified NIC.
-func (s *Stack) GetNetworkEndpoint(nicID tcpip.NICID, proto tcpip.NetworkProtocolNumber) (NetworkEndpoint, *tcpip.Error) {
+func (s *Stack) GetNetworkEndpoint(nicID tcpip.NICID, proto tcpip.NetworkProtocolNumber) (NetworkEndpoint, tcpip.Error) {
s.mu.Lock()
defer s.mu.Unlock()
nic, ok := s.nics[nicID]
if !ok {
- return nil, tcpip.ErrUnknownNICID
+ return nil, &tcpip.ErrUnknownNICID{}
}
return nic.getNetworkEndpoint(proto), nil
}
// NUDConfigurations gets the per-interface NUD configurations.
-func (s *Stack) NUDConfigurations(id tcpip.NICID) (NUDConfigurations, *tcpip.Error) {
+func (s *Stack) NUDConfigurations(id tcpip.NICID, proto tcpip.NetworkProtocolNumber) (NUDConfigurations, tcpip.Error) {
s.mu.RLock()
nic, ok := s.nics[id]
s.mu.RUnlock()
if !ok {
- return NUDConfigurations{}, tcpip.ErrUnknownNICID
+ return NUDConfigurations{}, &tcpip.ErrUnknownNICID{}
}
- return nic.nudConfigs()
+ return nic.nudConfigs(proto)
}
// SetNUDConfigurations sets the per-interface NUD configurations.
//
// Note, if c contains invalid NUD configuration values, it will be fixed to
// use default values for the erroneous values.
-func (s *Stack) SetNUDConfigurations(id tcpip.NICID, c NUDConfigurations) *tcpip.Error {
+func (s *Stack) SetNUDConfigurations(id tcpip.NICID, proto tcpip.NetworkProtocolNumber, c NUDConfigurations) tcpip.Error {
s.mu.RLock()
nic, ok := s.nics[id]
s.mu.RUnlock()
if !ok {
- return tcpip.ErrUnknownNICID
+ return &tcpip.ErrUnknownNICID{}
}
- return nic.setNUDConfigs(c)
+ return nic.setNUDConfigs(proto, c)
}
// Seed returns a 32 bit value that can be used as a seed value for port
@@ -2056,7 +2063,7 @@ func generateRandInt64() int64 {
}
// FindNetworkEndpoint returns the network endpoint for the given address.
-func (s *Stack) FindNetworkEndpoint(netProto tcpip.NetworkProtocolNumber, address tcpip.Address) (NetworkEndpoint, *tcpip.Error) {
+func (s *Stack) FindNetworkEndpoint(netProto tcpip.NetworkProtocolNumber, address tcpip.Address) (NetworkEndpoint, tcpip.Error) {
s.mu.RLock()
defer s.mu.RUnlock()
@@ -2068,7 +2075,7 @@ func (s *Stack) FindNetworkEndpoint(netProto tcpip.NetworkProtocolNumber, addres
addressEndpoint.DecRef()
return nic.getNetworkEndpoint(netProto), nil
}
- return nil, tcpip.ErrBadAddress
+ return nil, &tcpip.ErrBadAddress{}
}
// FindNICNameFromID returns the name of the NIC for the given NICID.
diff --git a/pkg/tcpip/stack/stack_options.go b/pkg/tcpip/stack/stack_options.go
index 92e70f94e..3066f4ffd 100644
--- a/pkg/tcpip/stack/stack_options.go
+++ b/pkg/tcpip/stack/stack_options.go
@@ -15,6 +15,8 @@
package stack
import (
+ "time"
+
"gvisor.dev/gvisor/pkg/tcpip"
)
@@ -29,6 +31,10 @@ const (
// DefaultMaxBufferSize is the default maximum permitted size of a
// send/receive buffer.
DefaultMaxBufferSize = 4 << 20 // 4 MiB
+
+ // defaultTCPInvalidRateLimit is the default value for
+ // stack.TCPInvalidRateLimit.
+ defaultTCPInvalidRateLimit = 500 * time.Millisecond
)
// ReceiveBufferSizeOption is used by stack.(Stack*).Option/SetOption to
@@ -39,18 +45,22 @@ type ReceiveBufferSizeOption struct {
Max int
}
+// TCPInvalidRateLimitOption is used by stack.(Stack*).Option/SetOption to get/set
+// stack.tcpInvalidRateLimit.
+type TCPInvalidRateLimitOption time.Duration
+
// SetOption allows setting stack wide options.
-func (s *Stack) SetOption(option interface{}) *tcpip.Error {
+func (s *Stack) SetOption(option interface{}) tcpip.Error {
switch v := option.(type) {
case tcpip.SendBufferSizeOption:
// Make sure we don't allow lowering the buffer below minimum
// required for stack to work.
if v.Min < MinBufferSize {
- return tcpip.ErrInvalidOptionValue
+ return &tcpip.ErrInvalidOptionValue{}
}
if v.Default < v.Min || v.Default > v.Max {
- return tcpip.ErrInvalidOptionValue
+ return &tcpip.ErrInvalidOptionValue{}
}
s.mu.Lock()
@@ -62,11 +72,11 @@ func (s *Stack) SetOption(option interface{}) *tcpip.Error {
// Make sure we don't allow lowering the buffer below minimum
// required for stack to work.
if v.Min < MinBufferSize {
- return tcpip.ErrInvalidOptionValue
+ return &tcpip.ErrInvalidOptionValue{}
}
if v.Default < v.Min || v.Default > v.Max {
- return tcpip.ErrInvalidOptionValue
+ return &tcpip.ErrInvalidOptionValue{}
}
s.mu.Lock()
@@ -74,13 +84,22 @@ func (s *Stack) SetOption(option interface{}) *tcpip.Error {
s.mu.Unlock()
return nil
+ case TCPInvalidRateLimitOption:
+ if v < 0 {
+ return &tcpip.ErrInvalidOptionValue{}
+ }
+ s.mu.Lock()
+ s.tcpInvalidRateLimit = time.Duration(v)
+ s.mu.Unlock()
+ return nil
+
default:
- return tcpip.ErrUnknownProtocolOption
+ return &tcpip.ErrUnknownProtocolOption{}
}
}
// Option allows retrieving stack wide options.
-func (s *Stack) Option(option interface{}) *tcpip.Error {
+func (s *Stack) Option(option interface{}) tcpip.Error {
switch v := option.(type) {
case *tcpip.SendBufferSizeOption:
s.mu.RLock()
@@ -94,7 +113,13 @@ func (s *Stack) Option(option interface{}) *tcpip.Error {
s.mu.RUnlock()
return nil
+ case *TCPInvalidRateLimitOption:
+ s.mu.RLock()
+ *v = TCPInvalidRateLimitOption(s.tcpInvalidRateLimit)
+ s.mu.RUnlock()
+ return nil
+
default:
- return tcpip.ErrUnknownProtocolOption
+ return &tcpip.ErrUnknownProtocolOption{}
}
}
diff --git a/pkg/tcpip/stack/stack_test.go b/pkg/tcpip/stack/stack_test.go
index 0f02f1d53..b641a4aaa 100644
--- a/pkg/tcpip/stack/stack_test.go
+++ b/pkg/tcpip/stack/stack_test.go
@@ -31,6 +31,7 @@ import (
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
+ "gvisor.dev/gvisor/pkg/tcpip/faketime"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
"gvisor.dev/gvisor/pkg/tcpip/link/loopback"
@@ -90,7 +91,7 @@ type fakeNetworkEndpoint struct {
dispatcher stack.TransportDispatcher
}
-func (f *fakeNetworkEndpoint) Enable() *tcpip.Error {
+func (f *fakeNetworkEndpoint) Enable() tcpip.Error {
f.mu.Lock()
defer f.mu.Unlock()
f.mu.enabled = true
@@ -137,12 +138,15 @@ func (f *fakeNetworkEndpoint) HandlePacket(pkt *stack.PacketBuffer) {
return
}
pkt.Data.TrimFront(fakeNetHeaderLen)
- f.dispatcher.DeliverTransportControlPacket(
+ f.dispatcher.DeliverTransportError(
tcpip.Address(nb[srcAddrOffset:srcAddrOffset+1]),
tcpip.Address(nb[dstAddrOffset:dstAddrOffset+1]),
fakeNetNumber,
tcpip.TransportProtocolNumber(nb[protocolNumberOffset]),
- stack.ControlPortUnreachable, 0, pkt)
+ // Nothing checks the error.
+ nil, /* transport error */
+ pkt,
+ )
return
}
@@ -162,7 +166,7 @@ func (f *fakeNetworkEndpoint) NetworkProtocolNumber() tcpip.NetworkProtocolNumbe
return f.proto.Number()
}
-func (f *fakeNetworkEndpoint) WritePacket(r *stack.Route, gso *stack.GSO, params stack.NetworkHeaderParams, pkt *stack.PacketBuffer) *tcpip.Error {
+func (f *fakeNetworkEndpoint) WritePacket(r *stack.Route, gso *stack.GSO, params stack.NetworkHeaderParams, pkt *stack.PacketBuffer) tcpip.Error {
// Increment the sent packet count in the protocol descriptor.
f.proto.sendPacketCount[int(r.RemoteAddress[0])%len(f.proto.sendPacketCount)]++
@@ -185,12 +189,12 @@ func (f *fakeNetworkEndpoint) WritePacket(r *stack.Route, gso *stack.GSO, params
}
// WritePackets implements stack.LinkEndpoint.WritePackets.
-func (*fakeNetworkEndpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.PacketBufferList, params stack.NetworkHeaderParams) (int, *tcpip.Error) {
+func (*fakeNetworkEndpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.PacketBufferList, params stack.NetworkHeaderParams) (int, tcpip.Error) {
panic("not implemented")
}
-func (*fakeNetworkEndpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBuffer) *tcpip.Error {
- return tcpip.ErrNotSupported
+func (*fakeNetworkEndpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBuffer) tcpip.Error {
+ return &tcpip.ErrNotSupported{}
}
func (f *fakeNetworkEndpoint) Close() {
@@ -243,7 +247,7 @@ func (*fakeNetworkProtocol) ParseAddresses(v buffer.View) (src, dst tcpip.Addres
return tcpip.Address(v[srcAddrOffset : srcAddrOffset+1]), tcpip.Address(v[dstAddrOffset : dstAddrOffset+1])
}
-func (f *fakeNetworkProtocol) NewEndpoint(nic stack.NetworkInterface, _ stack.LinkAddressCache, _ stack.NUDHandler, dispatcher stack.TransportDispatcher) stack.NetworkEndpoint {
+func (f *fakeNetworkProtocol) NewEndpoint(nic stack.NetworkInterface, dispatcher stack.TransportDispatcher) stack.NetworkEndpoint {
e := &fakeNetworkEndpoint{
nic: nic,
proto: f,
@@ -253,23 +257,23 @@ func (f *fakeNetworkProtocol) NewEndpoint(nic stack.NetworkInterface, _ stack.Li
return e
}
-func (f *fakeNetworkProtocol) SetOption(option tcpip.SettableNetworkProtocolOption) *tcpip.Error {
+func (f *fakeNetworkProtocol) SetOption(option tcpip.SettableNetworkProtocolOption) tcpip.Error {
switch v := option.(type) {
case *tcpip.DefaultTTLOption:
f.defaultTTL = uint8(*v)
return nil
default:
- return tcpip.ErrUnknownProtocolOption
+ return &tcpip.ErrUnknownProtocolOption{}
}
}
-func (f *fakeNetworkProtocol) Option(option tcpip.GettableNetworkProtocolOption) *tcpip.Error {
+func (f *fakeNetworkProtocol) Option(option tcpip.GettableNetworkProtocolOption) tcpip.Error {
switch v := option.(type) {
case *tcpip.DefaultTTLOption:
*v = tcpip.DefaultTTLOption(f.defaultTTL)
return nil
default:
- return tcpip.ErrUnknownProtocolOption
+ return &tcpip.ErrUnknownProtocolOption{}
}
}
@@ -418,7 +422,7 @@ func TestNetworkReceive(t *testing.T) {
}
}
-func sendTo(s *stack.Stack, addr tcpip.Address, payload buffer.View) *tcpip.Error {
+func sendTo(s *stack.Stack, addr tcpip.Address, payload buffer.View) tcpip.Error {
r, err := s.FindRoute(0, "", addr, fakeNetNumber, false /* multicastLoop */)
if err != nil {
return err
@@ -427,7 +431,7 @@ func sendTo(s *stack.Stack, addr tcpip.Address, payload buffer.View) *tcpip.Erro
return send(r, payload)
}
-func send(r *stack.Route, payload buffer.View) *tcpip.Error {
+func send(r *stack.Route, payload buffer.View) tcpip.Error {
return r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{Protocol: fakeTransNumber, TTL: 123, TOS: stack.DefaultTOS}, stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: int(r.MaxHeaderLength()),
Data: payload.ToVectorisedView(),
@@ -456,14 +460,14 @@ func testSend(t *testing.T, r *stack.Route, ep *channel.Endpoint, payload buffer
}
}
-func testFailingSend(t *testing.T, r *stack.Route, ep *channel.Endpoint, payload buffer.View, wantErr *tcpip.Error) {
+func testFailingSend(t *testing.T, r *stack.Route, ep *channel.Endpoint, payload buffer.View, wantErr tcpip.Error) {
t.Helper()
if gotErr := send(r, payload); gotErr != wantErr {
t.Errorf("send failed: got = %s, want = %s ", gotErr, wantErr)
}
}
-func testFailingSendTo(t *testing.T, s *stack.Stack, addr tcpip.Address, ep *channel.Endpoint, payload buffer.View, wantErr *tcpip.Error) {
+func testFailingSendTo(t *testing.T, s *stack.Stack, addr tcpip.Address, ep *channel.Endpoint, payload buffer.View, wantErr tcpip.Error) {
t.Helper()
if gotErr := sendTo(s, addr, payload); gotErr != wantErr {
t.Errorf("sendto failed: got = %s, want = %s ", gotErr, wantErr)
@@ -600,8 +604,8 @@ func testRoute(t *testing.T, s *stack.Stack, nic tcpip.NICID, srcAddr, dstAddr,
func testNoRoute(t *testing.T, s *stack.Stack, nic tcpip.NICID, srcAddr, dstAddr tcpip.Address) {
_, err := s.FindRoute(nic, srcAddr, dstAddr, fakeNetNumber, false /* multicastLoop */)
- if err != tcpip.ErrNoRoute {
- t.Fatalf("FindRoute returned unexpected error, got = %v, want = %s", err, tcpip.ErrNoRoute)
+ if _, ok := err.(*tcpip.ErrNoRoute); !ok {
+ t.Fatalf("FindRoute returned unexpected error, got = %v, want = %s", err, &tcpip.ErrNoRoute{})
}
}
@@ -649,8 +653,9 @@ func TestDisableUnknownNIC(t *testing.T) {
NetworkProtocols: []stack.NetworkProtocolFactory{fakeNetFactory},
})
- if err := s.DisableNIC(1); err != tcpip.ErrUnknownNICID {
- t.Fatalf("got s.DisableNIC(1) = %v, want = %s", err, tcpip.ErrUnknownNICID)
+ err := s.DisableNIC(1)
+ if _, ok := err.(*tcpip.ErrUnknownNICID); !ok {
+ t.Fatalf("got s.DisableNIC(1) = %v, want = %s", err, &tcpip.ErrUnknownNICID{})
}
}
@@ -708,8 +713,9 @@ func TestRemoveUnknownNIC(t *testing.T) {
NetworkProtocols: []stack.NetworkProtocolFactory{fakeNetFactory},
})
- if err := s.RemoveNIC(1); err != tcpip.ErrUnknownNICID {
- t.Fatalf("got s.RemoveNIC(1) = %v, want = %s", err, tcpip.ErrUnknownNICID)
+ err := s.RemoveNIC(1)
+ if _, ok := err.(*tcpip.ErrUnknownNICID); !ok {
+ t.Fatalf("got s.RemoveNIC(1) = %v, want = %s", err, &tcpip.ErrUnknownNICID{})
}
}
@@ -752,8 +758,8 @@ func TestRemoveNIC(t *testing.T) {
func TestRouteWithDownNIC(t *testing.T) {
tests := []struct {
name string
- downFn func(s *stack.Stack, nicID tcpip.NICID) *tcpip.Error
- upFn func(s *stack.Stack, nicID tcpip.NICID) *tcpip.Error
+ downFn func(s *stack.Stack, nicID tcpip.NICID) tcpip.Error
+ upFn func(s *stack.Stack, nicID tcpip.NICID) tcpip.Error
}{
{
name: "Disabled NIC",
@@ -911,15 +917,15 @@ func TestRouteWithDownNIC(t *testing.T) {
if err := test.downFn(s, nicID1); err != nil {
t.Fatalf("test.downFn(_, %d): %s", nicID1, err)
}
- testFailingSend(t, r1, ep1, buf, tcpip.ErrInvalidEndpointState)
+ testFailingSend(t, r1, ep1, buf, &tcpip.ErrInvalidEndpointState{})
testSend(t, r2, ep2, buf)
// Writes with Routes that use NIC2 after being brought down should fail.
if err := test.downFn(s, nicID2); err != nil {
t.Fatalf("test.downFn(_, %d): %s", nicID2, err)
}
- testFailingSend(t, r1, ep1, buf, tcpip.ErrInvalidEndpointState)
- testFailingSend(t, r2, ep2, buf, tcpip.ErrInvalidEndpointState)
+ testFailingSend(t, r1, ep1, buf, &tcpip.ErrInvalidEndpointState{})
+ testFailingSend(t, r2, ep2, buf, &tcpip.ErrInvalidEndpointState{})
if upFn := test.upFn; upFn != nil {
// Writes with Routes that use NIC1 after being brought up should
@@ -932,7 +938,7 @@ func TestRouteWithDownNIC(t *testing.T) {
t.Fatalf("test.upFn(_, %d): %s", nicID1, err)
}
testSend(t, r1, ep1, buf)
- testFailingSend(t, r2, ep2, buf, tcpip.ErrInvalidEndpointState)
+ testFailingSend(t, r2, ep2, buf, &tcpip.ErrInvalidEndpointState{})
}
})
}
@@ -1057,11 +1063,12 @@ func TestAddressRemoval(t *testing.T) {
t.Fatal("RemoveAddress failed:", err)
}
testFailingRecv(t, fakeNet, localAddrByte, ep, buf)
- testFailingSendTo(t, s, remoteAddr, ep, nil, tcpip.ErrNoRoute)
+ testFailingSendTo(t, s, remoteAddr, ep, nil, &tcpip.ErrNoRoute{})
// Check that removing the same address fails.
- if err := s.RemoveAddress(1, localAddr); err != tcpip.ErrBadLocalAddress {
- t.Fatalf("RemoveAddress returned unexpected error, got = %v, want = %s", err, tcpip.ErrBadLocalAddress)
+ err := s.RemoveAddress(1, localAddr)
+ if _, ok := err.(*tcpip.ErrBadLocalAddress); !ok {
+ t.Fatalf("RemoveAddress returned unexpected error, got = %v, want = %s", err, &tcpip.ErrBadLocalAddress{})
}
}
@@ -1108,12 +1115,15 @@ func TestAddressRemovalWithRouteHeld(t *testing.T) {
t.Fatal("RemoveAddress failed:", err)
}
testFailingRecv(t, fakeNet, localAddrByte, ep, buf)
- testFailingSend(t, r, ep, nil, tcpip.ErrInvalidEndpointState)
- testFailingSendTo(t, s, remoteAddr, ep, nil, tcpip.ErrNoRoute)
+ testFailingSend(t, r, ep, nil, &tcpip.ErrInvalidEndpointState{})
+ testFailingSendTo(t, s, remoteAddr, ep, nil, &tcpip.ErrNoRoute{})
// Check that removing the same address fails.
- if err := s.RemoveAddress(1, localAddr); err != tcpip.ErrBadLocalAddress {
- t.Fatalf("RemoveAddress returned unexpected error, got = %v, want = %s", err, tcpip.ErrBadLocalAddress)
+ {
+ err := s.RemoveAddress(1, localAddr)
+ if _, ok := err.(*tcpip.ErrBadLocalAddress); !ok {
+ t.Fatalf("RemoveAddress returned unexpected error, got = %v, want = %s", err, &tcpip.ErrBadLocalAddress{})
+ }
}
}
@@ -1207,7 +1217,7 @@ func TestEndpointExpiration(t *testing.T) {
// FIXME(b/139841518):Spoofing doesn't work if there is no primary address.
// testSendTo(t, s, remoteAddr, ep, nil)
} else {
- testFailingSendTo(t, s, remoteAddr, ep, nil, tcpip.ErrNoRoute)
+ testFailingSendTo(t, s, remoteAddr, ep, nil, &tcpip.ErrNoRoute{})
}
// 2. Add Address, everything should work.
@@ -1235,7 +1245,7 @@ func TestEndpointExpiration(t *testing.T) {
// FIXME(b/139841518):Spoofing doesn't work if there is no primary address.
// testSendTo(t, s, remoteAddr, ep, nil)
} else {
- testFailingSendTo(t, s, remoteAddr, ep, nil, tcpip.ErrNoRoute)
+ testFailingSendTo(t, s, remoteAddr, ep, nil, &tcpip.ErrNoRoute{})
}
// 4. Add Address back, everything should work again.
@@ -1274,8 +1284,8 @@ func TestEndpointExpiration(t *testing.T) {
testSend(t, r, ep, nil)
testSendTo(t, s, remoteAddr, ep, nil)
} else {
- testFailingSend(t, r, ep, nil, tcpip.ErrInvalidEndpointState)
- testFailingSendTo(t, s, remoteAddr, ep, nil, tcpip.ErrNoRoute)
+ testFailingSend(t, r, ep, nil, &tcpip.ErrInvalidEndpointState{})
+ testFailingSendTo(t, s, remoteAddr, ep, nil, &tcpip.ErrNoRoute{})
}
// 7. Add Address back, everything should work again.
@@ -1311,7 +1321,7 @@ func TestEndpointExpiration(t *testing.T) {
// FIXME(b/139841518):Spoofing doesn't work if there is no primary address.
// testSendTo(t, s, remoteAddr, ep, nil)
} else {
- testFailingSendTo(t, s, remoteAddr, ep, nil, tcpip.ErrNoRoute)
+ testFailingSendTo(t, s, remoteAddr, ep, nil, &tcpip.ErrNoRoute{})
}
})
}
@@ -1354,8 +1364,8 @@ func TestPromiscuousMode(t *testing.T) {
// Check that we can't get a route as there is no local address.
_, err := s.FindRoute(0, "", "\x02", fakeNetNumber, false /* multicastLoop */)
- if err != tcpip.ErrNoRoute {
- t.Fatalf("FindRoute returned unexpected error: got = %v, want = %s", err, tcpip.ErrNoRoute)
+ if _, ok := err.(*tcpip.ErrNoRoute); !ok {
+ t.Fatalf("FindRoute returned unexpected error: got = %v, want = %s", err, &tcpip.ErrNoRoute{})
}
// Set promiscuous mode to false, then check that packet can't be
@@ -1561,7 +1571,7 @@ func TestSpoofingNoAddress(t *testing.T) {
t.Errorf("FindRoute succeeded with route %+v when it should have failed", r)
}
// Sending a packet fails.
- testFailingSendTo(t, s, dstAddr, ep, nil, tcpip.ErrNoRoute)
+ testFailingSendTo(t, s, dstAddr, ep, nil, &tcpip.ErrNoRoute{})
// With address spoofing enabled, FindRoute permits any address to be used
// as the source.
@@ -1611,8 +1621,11 @@ func TestOutgoingBroadcastWithEmptyRouteTable(t *testing.T) {
s.SetRouteTable([]tcpip.Route{})
// If there is no endpoint, it won't work.
- if _, err := s.FindRoute(1, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, false /* multicastLoop */); err != tcpip.ErrNetworkUnreachable {
- t.Fatalf("got FindRoute(1, %s, %s, %d) = %s, want = %s", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err, tcpip.ErrNetworkUnreachable)
+ {
+ _, err := s.FindRoute(1, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, false /* multicastLoop */)
+ if _, ok := err.(*tcpip.ErrNetworkUnreachable); !ok {
+ t.Fatalf("got FindRoute(1, %s, %s, %d) = %s, want = %s", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err, &tcpip.ErrNetworkUnreachable{})
+ }
}
protoAddr := tcpip.ProtocolAddress{Protocol: fakeNetNumber, AddressWithPrefix: tcpip.AddressWithPrefix{header.IPv4Any, 0}}
@@ -1631,8 +1644,11 @@ func TestOutgoingBroadcastWithEmptyRouteTable(t *testing.T) {
}
// If the NIC doesn't exist, it won't work.
- if _, err := s.FindRoute(2, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, false /* multicastLoop */); err != tcpip.ErrNetworkUnreachable {
- t.Fatalf("got FindRoute(2, %v, %v, %d) = %v want = %v", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err, tcpip.ErrNetworkUnreachable)
+ {
+ _, err := s.FindRoute(2, header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, false /* multicastLoop */)
+ if _, ok := err.(*tcpip.ErrNetworkUnreachable); !ok {
+ t.Fatalf("got FindRoute(2, %v, %v, %d) = %v want = %v", header.IPv4Any, header.IPv4Broadcast, fakeNetNumber, err, &tcpip.ErrNetworkUnreachable{})
+ }
}
}
@@ -1774,9 +1790,9 @@ func TestMulticastOrIPv6LinkLocalNeedsNoRoute(t *testing.T) {
anyAddr = header.IPv6Any
}
- want := tcpip.ErrNetworkUnreachable
+ var want tcpip.Error = &tcpip.ErrNetworkUnreachable{}
if tc.routeNeeded {
- want = tcpip.ErrNoRoute
+ want = &tcpip.ErrNoRoute{}
}
// If there is no endpoint, it won't work.
@@ -1790,8 +1806,8 @@ func TestMulticastOrIPv6LinkLocalNeedsNoRoute(t *testing.T) {
if r, err := s.FindRoute(1, anyAddr, tc.address, fakeNetNumber, false /* multicastLoop */); tc.routeNeeded {
// Route table is empty but we need a route, this should cause an error.
- if err != tcpip.ErrNoRoute {
- t.Fatalf("got FindRoute(1, %v, %v, %v) = %v, want = %v", anyAddr, tc.address, fakeNetNumber, err, tcpip.ErrNoRoute)
+ if _, ok := err.(*tcpip.ErrNoRoute); !ok {
+ t.Fatalf("got FindRoute(1, %v, %v, %v) = %v, want = %v", anyAddr, tc.address, fakeNetNumber, err, &tcpip.ErrNoRoute{})
}
} else {
if err != nil {
@@ -2115,7 +2131,7 @@ func TestCreateNICWithOptions(t *testing.T) {
type callArgsAndExpect struct {
nicID tcpip.NICID
opts stack.NICOptions
- err *tcpip.Error
+ err tcpip.Error
}
tests := []struct {
@@ -2133,7 +2149,7 @@ func TestCreateNICWithOptions(t *testing.T) {
{
nicID: tcpip.NICID(1),
opts: stack.NICOptions{Name: "eth2"},
- err: tcpip.ErrDuplicateNICID,
+ err: &tcpip.ErrDuplicateNICID{},
},
},
},
@@ -2148,7 +2164,7 @@ func TestCreateNICWithOptions(t *testing.T) {
{
nicID: tcpip.NICID(2),
opts: stack.NICOptions{Name: "lo"},
- err: tcpip.ErrDuplicateNICID,
+ err: &tcpip.ErrDuplicateNICID{},
},
},
},
@@ -2178,7 +2194,7 @@ func TestCreateNICWithOptions(t *testing.T) {
{
nicID: tcpip.NICID(1),
opts: stack.NICOptions{},
- err: tcpip.ErrDuplicateNICID,
+ err: &tcpip.ErrDuplicateNICID{},
},
},
},
@@ -3297,14 +3313,14 @@ func TestStackReceiveBufferSizeOption(t *testing.T) {
testCases := []struct {
name string
rs stack.ReceiveBufferSizeOption
- err *tcpip.Error
+ err tcpip.Error
}{
// Invalid configurations.
- {"min_below_zero", stack.ReceiveBufferSizeOption{Min: -1, Default: sMin, Max: sMin}, tcpip.ErrInvalidOptionValue},
- {"min_zero", stack.ReceiveBufferSizeOption{Min: 0, Default: sMin, Max: sMin}, tcpip.ErrInvalidOptionValue},
- {"default_below_min", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin - 1, Max: sMin - 1}, tcpip.ErrInvalidOptionValue},
- {"default_above_max", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin}, tcpip.ErrInvalidOptionValue},
- {"max_below_min", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin - 1}, tcpip.ErrInvalidOptionValue},
+ {"min_below_zero", stack.ReceiveBufferSizeOption{Min: -1, Default: sMin, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
+ {"min_zero", stack.ReceiveBufferSizeOption{Min: 0, Default: sMin, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
+ {"default_below_min", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin - 1, Max: sMin - 1}, &tcpip.ErrInvalidOptionValue{}},
+ {"default_above_max", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
+ {"max_below_min", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin - 1}, &tcpip.ErrInvalidOptionValue{}},
// Valid Configurations
{"in_ascending_order", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 2}, nil},
@@ -3337,14 +3353,14 @@ func TestStackSendBufferSizeOption(t *testing.T) {
testCases := []struct {
name string
ss tcpip.SendBufferSizeOption
- err *tcpip.Error
+ err tcpip.Error
}{
// Invalid configurations.
- {"min_below_zero", tcpip.SendBufferSizeOption{Min: -1, Default: sMin, Max: sMin}, tcpip.ErrInvalidOptionValue},
- {"min_zero", tcpip.SendBufferSizeOption{Min: 0, Default: sMin, Max: sMin}, tcpip.ErrInvalidOptionValue},
- {"default_below_min", tcpip.SendBufferSizeOption{Min: 0, Default: sMin - 1, Max: sMin - 1}, tcpip.ErrInvalidOptionValue},
- {"default_above_max", tcpip.SendBufferSizeOption{Min: 0, Default: sMin + 1, Max: sMin}, tcpip.ErrInvalidOptionValue},
- {"max_below_min", tcpip.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin - 1}, tcpip.ErrInvalidOptionValue},
+ {"min_below_zero", tcpip.SendBufferSizeOption{Min: -1, Default: sMin, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
+ {"min_zero", tcpip.SendBufferSizeOption{Min: 0, Default: sMin, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
+ {"default_below_min", tcpip.SendBufferSizeOption{Min: 0, Default: sMin - 1, Max: sMin - 1}, &tcpip.ErrInvalidOptionValue{}},
+ {"default_above_max", tcpip.SendBufferSizeOption{Min: 0, Default: sMin + 1, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
+ {"max_below_min", tcpip.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin - 1}, &tcpip.ErrInvalidOptionValue{}},
// Valid Configurations
{"in_ascending_order", tcpip.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 2}, nil},
@@ -3356,11 +3372,12 @@ func TestStackSendBufferSizeOption(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
s := stack.New(stack.Options{})
defer s.Close()
- if err := s.SetOption(tc.ss); err != tc.err {
- t.Fatalf("s.SetOption(%+v) = %v, want: %v", tc.ss, err, tc.err)
+ err := s.SetOption(tc.ss)
+ if diff := cmp.Diff(tc.err, err); diff != "" {
+ t.Fatalf("unexpected error from s.SetOption(%+v), (-want, +got):\n%s", tc.ss, diff)
}
- var ss tcpip.SendBufferSizeOption
if tc.err == nil {
+ var ss tcpip.SendBufferSizeOption
if err := s.Option(&ss); err != nil {
t.Fatalf("s.Option(%+v) = %v, want: nil", ss, err)
}
@@ -3919,7 +3936,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
addrNIC tcpip.NICID
localAddr tcpip.Address
- findRouteErr *tcpip.Error
+ findRouteErr tcpip.Error
dependentOnForwarding bool
}{
{
@@ -3928,7 +3945,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
forwardingEnabled: false,
addrNIC: nicID1,
localAddr: fakeNetCfg.nic2Addr,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -3937,7 +3954,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
forwardingEnabled: true,
addrNIC: nicID1,
localAddr: fakeNetCfg.nic2Addr,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -3946,7 +3963,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
forwardingEnabled: false,
addrNIC: nicID1,
localAddr: fakeNetCfg.nic1Addr,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -3982,7 +3999,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
forwardingEnabled: false,
addrNIC: nicID2,
localAddr: fakeNetCfg.nic1Addr,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -3991,7 +4008,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
forwardingEnabled: true,
addrNIC: nicID2,
localAddr: fakeNetCfg.nic1Addr,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -4015,7 +4032,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: fakeNetCfg,
forwardingEnabled: false,
localAddr: fakeNetCfg.nic1Addr,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -4031,7 +4048,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: ipv6LinkLocalNIC1WithGlobalRemote,
forwardingEnabled: false,
addrNIC: nicID1,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -4039,7 +4056,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: ipv6LinkLocalNIC1WithGlobalRemote,
forwardingEnabled: true,
addrNIC: nicID1,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -4047,7 +4064,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: ipv6LinkLocalNIC1WithGlobalRemote,
forwardingEnabled: false,
localAddr: ipv6LinkLocalNIC1WithGlobalRemote.nic1Addr,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -4055,7 +4072,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: ipv6LinkLocalNIC1WithGlobalRemote,
forwardingEnabled: true,
localAddr: ipv6LinkLocalNIC1WithGlobalRemote.nic1Addr,
- findRouteErr: tcpip.ErrNoRoute,
+ findRouteErr: &tcpip.ErrNoRoute{},
dependentOnForwarding: false,
},
{
@@ -4087,7 +4104,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: ipv6GlobalNIC1WithLinkLocalRemote,
forwardingEnabled: false,
localAddr: ipv6GlobalNIC1WithLinkLocalRemote.nic1Addr,
- findRouteErr: tcpip.ErrNetworkUnreachable,
+ findRouteErr: &tcpip.ErrNetworkUnreachable{},
dependentOnForwarding: false,
},
{
@@ -4095,7 +4112,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: ipv6GlobalNIC1WithLinkLocalRemote,
forwardingEnabled: true,
localAddr: ipv6GlobalNIC1WithLinkLocalRemote.nic1Addr,
- findRouteErr: tcpip.ErrNetworkUnreachable,
+ findRouteErr: &tcpip.ErrNetworkUnreachable{},
dependentOnForwarding: false,
},
{
@@ -4103,7 +4120,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: ipv6GlobalNIC1WithLinkLocalMulticastRemote,
forwardingEnabled: false,
localAddr: ipv6GlobalNIC1WithLinkLocalMulticastRemote.nic1Addr,
- findRouteErr: tcpip.ErrNetworkUnreachable,
+ findRouteErr: &tcpip.ErrNetworkUnreachable{},
dependentOnForwarding: false,
},
{
@@ -4111,7 +4128,7 @@ func TestFindRouteWithForwarding(t *testing.T) {
netCfg: ipv6GlobalNIC1WithLinkLocalMulticastRemote,
forwardingEnabled: true,
localAddr: ipv6GlobalNIC1WithLinkLocalMulticastRemote.nic1Addr,
- findRouteErr: tcpip.ErrNetworkUnreachable,
+ findRouteErr: &tcpip.ErrNetworkUnreachable{},
dependentOnForwarding: false,
},
{
@@ -4166,8 +4183,8 @@ func TestFindRouteWithForwarding(t *testing.T) {
if r != nil {
defer r.Release()
}
- if err != test.findRouteErr {
- t.Fatalf("FindRoute(%d, %s, %s, %d, false) = %s, want = %s", test.addrNIC, test.localAddr, test.netCfg.remoteAddr, test.netCfg.proto, err, test.findRouteErr)
+ if diff := cmp.Diff(test.findRouteErr, err); diff != "" {
+ t.Fatalf("unexpected error from FindRoute(%d, %s, %s, %d, false), (-want, +got):\n%s", test.addrNIC, test.localAddr, test.netCfg.remoteAddr, test.netCfg.proto, diff)
}
if test.findRouteErr != nil {
@@ -4214,8 +4231,11 @@ func TestFindRouteWithForwarding(t *testing.T) {
if err := s.SetForwarding(test.netCfg.proto, false); err != nil {
t.Fatalf("SetForwarding(%d, false): %s", test.netCfg.proto, err)
}
- if err := send(r, data); err != tcpip.ErrInvalidEndpointState {
- t.Fatalf("got send(_, _) = %s, want = %s", err, tcpip.ErrInvalidEndpointState)
+ {
+ err := send(r, data)
+ if _, ok := err.(*tcpip.ErrInvalidEndpointState); !ok {
+ t.Fatalf("got send(_, _) = %s, want = %s", err, &tcpip.ErrInvalidEndpointState{})
+ }
}
if n := ep1.Drain(); n != 0 {
t.Errorf("got %d unexpected packets from ep1", n)
@@ -4277,8 +4297,9 @@ func TestWritePacketToRemote(t *testing.T) {
}
t.Run("InvalidNICID", func(t *testing.T) {
- if got, want := s.WritePacketToRemote(234, linkAddr2, header.IPv4ProtocolNumber, buffer.View([]byte{1}).ToVectorisedView()), tcpip.ErrUnknownDevice; got != want {
- t.Fatalf("s.WritePacketToRemote(_, _, _, _) = %s, want = %s", got, want)
+ err := s.WritePacketToRemote(234, linkAddr2, header.IPv4ProtocolNumber, buffer.View([]byte{1}).ToVectorisedView())
+ if _, ok := err.(*tcpip.ErrUnknownDevice); !ok {
+ t.Fatalf("s.WritePacketToRemote(_, _, _, _) = %s, want = %s", err, &tcpip.ErrUnknownDevice{})
}
pkt, ok := e.Read()
if got, want := ok, false; got != want {
@@ -4296,9 +4317,11 @@ func TestClearNeighborCacheOnNICDisable(t *testing.T) {
linkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06")
)
+ clock := faketime.NewManualClock()
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
UseNeighborCache: true,
+ Clock: clock,
})
e := channel.New(0, 0, "")
e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
@@ -4306,36 +4329,56 @@ func TestClearNeighborCacheOnNICDisable(t *testing.T) {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- if err := s.AddStaticNeighbor(nicID, ipv4Addr, linkAddr); err != nil {
- t.Fatalf("s.AddStaticNeighbor(%d, %s, %s): %s", nicID, ipv4Addr, linkAddr, err)
- }
- if err := s.AddStaticNeighbor(nicID, ipv6Addr, linkAddr); err != nil {
- t.Fatalf("s.AddStaticNeighbor(%d, %s, %s): %s", nicID, ipv6Addr, linkAddr, err)
+ addrs := []struct {
+ proto tcpip.NetworkProtocolNumber
+ addr tcpip.Address
+ }{
+ {
+ proto: ipv4.ProtocolNumber,
+ addr: ipv4Addr,
+ },
+ {
+ proto: ipv6.ProtocolNumber,
+ addr: ipv6Addr,
+ },
}
- if neighbors, err := s.Neighbors(nicID); err != nil {
- t.Fatalf("s.Neighbors(%d): %s", nicID, err)
- } else if len(neighbors) != 2 {
- t.Fatalf("got len(neighbors) = %d, want = 2; neighbors = %#v", len(neighbors), neighbors)
+ for _, addr := range addrs {
+ if err := s.AddStaticNeighbor(nicID, addr.proto, addr.addr, linkAddr); err != nil {
+ t.Fatalf("s.AddStaticNeighbor(%d, %d, %s, %s): %s", nicID, addr.proto, addr.addr, linkAddr, err)
+ }
+
+ if neighbors, err := s.Neighbors(nicID, addr.proto); err != nil {
+ t.Fatalf("s.Neighbors(%d, %d): %s", nicID, addr.proto, err)
+ } else if diff := cmp.Diff(
+ []stack.NeighborEntry{{Addr: addr.addr, LinkAddr: linkAddr, State: stack.Static, UpdatedAtNanos: clock.NowNanoseconds()}},
+ neighbors,
+ ); diff != "" {
+ t.Fatalf("proto=%d neighbors mismatch (-want +got):\n%s", addr.proto, diff)
+ }
}
// Disabling the NIC should clear the neighbor table.
if err := s.DisableNIC(nicID); err != nil {
t.Fatalf("s.DisableNIC(%d): %s", nicID, err)
}
- if neighbors, err := s.Neighbors(nicID); err != nil {
- t.Fatalf("s.Neighbors(%d): %s", nicID, err)
- } else if len(neighbors) != 0 {
- t.Fatalf("got len(neighbors) = %d, want = 0; neighbors = %#v", len(neighbors), neighbors)
+ for _, addr := range addrs {
+ if neighbors, err := s.Neighbors(nicID, addr.proto); err != nil {
+ t.Fatalf("s.Neighbors(%d, %d): %s", nicID, addr.proto, err)
+ } else if len(neighbors) != 0 {
+ t.Fatalf("got proto=%d len(neighbors) = %d, want = 0; neighbors = %#v", addr.proto, len(neighbors), neighbors)
+ }
}
// Enabling the NIC should have an empty neighbor table.
if err := s.EnableNIC(nicID); err != nil {
t.Fatalf("s.EnableNIC(%d): %s", nicID, err)
}
- if neighbors, err := s.Neighbors(nicID); err != nil {
- t.Fatalf("s.Neighbors(%d): %s", nicID, err)
- } else if len(neighbors) != 0 {
- t.Fatalf("got len(neighbors) = %d, want = 0; neighbors = %#v", len(neighbors), neighbors)
+ for _, addr := range addrs {
+ if neighbors, err := s.Neighbors(nicID, addr.proto); err != nil {
+ t.Fatalf("s.Neighbors(%d, %d): %s", nicID, addr.proto, err)
+ } else if len(neighbors) != 0 {
+ t.Fatalf("got proto=%d len(neighbors) = %d, want = 0; neighbors = %#v", addr.proto, len(neighbors), neighbors)
+ }
}
}
@@ -4352,11 +4395,17 @@ func TestGetLinkAddressErrors(t *testing.T) {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
- if err := s.GetLinkAddress(unknownNICID, "", "", ipv4.ProtocolNumber, nil); err != tcpip.ErrUnknownNICID {
- t.Errorf("got s.GetLinkAddress(%d, '', '', %d, nil) = %s, want = %s", unknownNICID, ipv4.ProtocolNumber, err, tcpip.ErrUnknownNICID)
+ {
+ err := s.GetLinkAddress(unknownNICID, "", "", ipv4.ProtocolNumber, nil)
+ if _, ok := err.(*tcpip.ErrUnknownNICID); !ok {
+ t.Errorf("got s.GetLinkAddress(%d, '', '', %d, nil) = %s, want = %s", unknownNICID, ipv4.ProtocolNumber, err, &tcpip.ErrUnknownNICID{})
+ }
}
- if err := s.GetLinkAddress(nicID, "", "", ipv4.ProtocolNumber, nil); err != tcpip.ErrNotSupported {
- t.Errorf("got s.GetLinkAddress(%d, '', '', %d, nil) = %s, want = %s", unknownNICID, ipv4.ProtocolNumber, err, tcpip.ErrNotSupported)
+ {
+ err := s.GetLinkAddress(nicID, "", "", ipv4.ProtocolNumber, nil)
+ if _, ok := err.(*tcpip.ErrNotSupported); !ok {
+ t.Errorf("got s.GetLinkAddress(%d, '', '', %d, nil) = %s, want = %s", unknownNICID, ipv4.ProtocolNumber, err, &tcpip.ErrNotSupported{})
+ }
}
}
@@ -4368,7 +4417,9 @@ func TestStaticGetLinkAddress(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
})
- if err := s.CreateNIC(nicID, channel.New(0, 0, "")); err != nil {
+ e := channel.New(0, 0, "")
+ e.LinkEPCapabilities |= stack.CapabilityResolutionRequired
+ if err := s.CreateNIC(nicID, e); err != nil {
t.Fatalf("CreateNIC(%d, _) = %s", nicID, err)
}
diff --git a/pkg/tcpip/stack/transport_demuxer.go b/pkg/tcpip/stack/transport_demuxer.go
index 07b2818d2..7d8d0851e 100644
--- a/pkg/tcpip/stack/transport_demuxer.go
+++ b/pkg/tcpip/stack/transport_demuxer.go
@@ -182,9 +182,8 @@ func (epsByNIC *endpointsByNIC) handlePacket(id TransportEndpointID, pkt *Packet
epsByNIC.mu.RUnlock() // Don't use defer for performance reasons.
}
-// handleControlPacket delivers a control packet to the transport endpoint
-// identified by id.
-func (epsByNIC *endpointsByNIC) handleControlPacket(n *NIC, id TransportEndpointID, typ ControlType, extra uint32, pkt *PacketBuffer) {
+// handleError delivers an error to the transport endpoint identified by id.
+func (epsByNIC *endpointsByNIC) handleError(n *NIC, id TransportEndpointID, transErr TransportError, pkt *PacketBuffer) {
epsByNIC.mu.RLock()
defer epsByNIC.mu.RUnlock()
@@ -200,12 +199,12 @@ func (epsByNIC *endpointsByNIC) handleControlPacket(n *NIC, id TransportEndpoint
// broadcast like we are doing with handlePacket above?
// multiPortEndpoints are guaranteed to have at least one element.
- selectEndpoint(id, mpep, epsByNIC.seed).HandleControlPacket(typ, extra, pkt)
+ selectEndpoint(id, mpep, epsByNIC.seed).HandleError(transErr, pkt)
}
// registerEndpoint returns true if it succeeds. It fails and returns
// false if ep already has an element with the same key.
-func (epsByNIC *endpointsByNIC) registerEndpoint(d *transportDemuxer, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, t TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) *tcpip.Error {
+func (epsByNIC *endpointsByNIC) registerEndpoint(d *transportDemuxer, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, t TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
epsByNIC.mu.Lock()
defer epsByNIC.mu.Unlock()
@@ -222,7 +221,7 @@ func (epsByNIC *endpointsByNIC) registerEndpoint(d *transportDemuxer, netProto t
return multiPortEp.singleRegisterEndpoint(t, flags)
}
-func (epsByNIC *endpointsByNIC) checkEndpoint(d *transportDemuxer, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, flags ports.Flags, bindToDevice tcpip.NICID) *tcpip.Error {
+func (epsByNIC *endpointsByNIC) checkEndpoint(d *transportDemuxer, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
epsByNIC.mu.RLock()
defer epsByNIC.mu.RUnlock()
@@ -294,7 +293,7 @@ func newTransportDemuxer(stack *Stack) *transportDemuxer {
// registerEndpoint registers the given endpoint with the dispatcher such that
// packets that match the endpoint ID are delivered to it.
-func (d *transportDemuxer) registerEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) *tcpip.Error {
+func (d *transportDemuxer) registerEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
for i, n := range netProtos {
if err := d.singleRegisterEndpoint(n, protocol, id, ep, flags, bindToDevice); err != nil {
d.unregisterEndpoint(netProtos[:i], protocol, id, ep, flags, bindToDevice)
@@ -306,7 +305,7 @@ func (d *transportDemuxer) registerEndpoint(netProtos []tcpip.NetworkProtocolNum
}
// checkEndpoint checks if an endpoint can be registered with the dispatcher.
-func (d *transportDemuxer) checkEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, flags ports.Flags, bindToDevice tcpip.NICID) *tcpip.Error {
+func (d *transportDemuxer) checkEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
for _, n := range netProtos {
if err := d.singleCheckEndpoint(n, protocol, id, flags, bindToDevice); err != nil {
return err
@@ -403,7 +402,7 @@ func (ep *multiPortEndpoint) handlePacketAll(id TransportEndpointID, pkt *Packet
// singleRegisterEndpoint tries to add an endpoint to the multiPortEndpoint
// list. The list might be empty already.
-func (ep *multiPortEndpoint) singleRegisterEndpoint(t TransportEndpoint, flags ports.Flags) *tcpip.Error {
+func (ep *multiPortEndpoint) singleRegisterEndpoint(t TransportEndpoint, flags ports.Flags) tcpip.Error {
ep.mu.Lock()
defer ep.mu.Unlock()
@@ -412,7 +411,7 @@ func (ep *multiPortEndpoint) singleRegisterEndpoint(t TransportEndpoint, flags p
if len(ep.endpoints) != 0 {
// If it was previously bound, we need to check if we can bind again.
if ep.flags.TotalRefs() > 0 && bits&ep.flags.IntersectionRefs() == 0 {
- return tcpip.ErrPortInUse
+ return &tcpip.ErrPortInUse{}
}
}
@@ -422,7 +421,7 @@ func (ep *multiPortEndpoint) singleRegisterEndpoint(t TransportEndpoint, flags p
return nil
}
-func (ep *multiPortEndpoint) singleCheckEndpoint(flags ports.Flags) *tcpip.Error {
+func (ep *multiPortEndpoint) singleCheckEndpoint(flags ports.Flags) tcpip.Error {
ep.mu.RLock()
defer ep.mu.RUnlock()
@@ -431,7 +430,7 @@ func (ep *multiPortEndpoint) singleCheckEndpoint(flags ports.Flags) *tcpip.Error
if len(ep.endpoints) != 0 {
// If it was previously bound, we need to check if we can bind again.
if ep.flags.TotalRefs() > 0 && bits&ep.flags.IntersectionRefs() == 0 {
- return tcpip.ErrPortInUse
+ return &tcpip.ErrPortInUse{}
}
}
@@ -456,7 +455,7 @@ func (ep *multiPortEndpoint) unregisterEndpoint(t TransportEndpoint, flags ports
return len(ep.endpoints) == 0
}
-func (d *transportDemuxer) singleRegisterEndpoint(netProto tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) *tcpip.Error {
+func (d *transportDemuxer) singleRegisterEndpoint(netProto tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, ep TransportEndpoint, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
if id.RemotePort != 0 {
// SO_REUSEPORT only applies to bound/listening endpoints.
flags.LoadBalanced = false
@@ -464,7 +463,7 @@ func (d *transportDemuxer) singleRegisterEndpoint(netProto tcpip.NetworkProtocol
eps, ok := d.protocol[protocolIDs{netProto, protocol}]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
eps.mu.Lock()
@@ -482,7 +481,7 @@ func (d *transportDemuxer) singleRegisterEndpoint(netProto tcpip.NetworkProtocol
return epsByNIC.registerEndpoint(d, netProto, protocol, ep, flags, bindToDevice)
}
-func (d *transportDemuxer) singleCheckEndpoint(netProto tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, flags ports.Flags, bindToDevice tcpip.NICID) *tcpip.Error {
+func (d *transportDemuxer) singleCheckEndpoint(netProto tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, id TransportEndpointID, flags ports.Flags, bindToDevice tcpip.NICID) tcpip.Error {
if id.RemotePort != 0 {
// SO_REUSEPORT only applies to bound/listening endpoints.
flags.LoadBalanced = false
@@ -490,7 +489,7 @@ func (d *transportDemuxer) singleCheckEndpoint(netProto tcpip.NetworkProtocolNum
eps, ok := d.protocol[protocolIDs{netProto, protocol}]
if !ok {
- return tcpip.ErrUnknownProtocol
+ return &tcpip.ErrUnknownProtocol{}
}
eps.mu.RLock()
@@ -596,9 +595,11 @@ func (d *transportDemuxer) deliverRawPacket(protocol tcpip.TransportProtocolNumb
return foundRaw
}
-// deliverControlPacket attempts to deliver the given control packet. Returns
-// true if it found an endpoint, false otherwise.
-func (d *transportDemuxer) deliverControlPacket(n *NIC, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, typ ControlType, extra uint32, pkt *PacketBuffer, id TransportEndpointID) bool {
+// deliverError attempts to deliver the given error to the appropriate transport
+// endpoint.
+//
+// Returns true if the error was delivered.
+func (d *transportDemuxer) deliverError(n *NIC, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr TransportError, pkt *PacketBuffer, id TransportEndpointID) bool {
eps, ok := d.protocol[protocolIDs{net, trans}]
if !ok {
return false
@@ -611,7 +612,7 @@ func (d *transportDemuxer) deliverControlPacket(n *NIC, net tcpip.NetworkProtoco
return false
}
- ep.handleControlPacket(n, id, typ, extra, pkt)
+ ep.handleError(n, id, transErr, pkt)
return true
}
@@ -649,10 +650,10 @@ func (d *transportDemuxer) findTransportEndpoint(netProto tcpip.NetworkProtocolN
// that packets of the appropriate protocol are delivered to it. A single
// packet can be sent to one or more raw endpoints along with a non-raw
// endpoint.
-func (d *transportDemuxer) registerRawEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) *tcpip.Error {
+func (d *transportDemuxer) registerRawEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) tcpip.Error {
eps, ok := d.protocol[protocolIDs{netProto, transProto}]
if !ok {
- return tcpip.ErrNotSupported
+ return &tcpip.ErrNotSupported{}
}
eps.mu.Lock()
diff --git a/pkg/tcpip/stack/transport_demuxer_test.go b/pkg/tcpip/stack/transport_demuxer_test.go
index de4b5fbdc..10cbbe589 100644
--- a/pkg/tcpip/stack/transport_demuxer_test.go
+++ b/pkg/tcpip/stack/transport_demuxer_test.go
@@ -175,9 +175,9 @@ func TestTransportDemuxerRegister(t *testing.T) {
for _, test := range []struct {
name string
proto tcpip.NetworkProtocolNumber
- want *tcpip.Error
+ want tcpip.Error
}{
- {"failure", ipv6.ProtocolNumber, tcpip.ErrUnknownProtocol},
+ {"failure", ipv6.ProtocolNumber, &tcpip.ErrUnknownProtocol{}},
{"success", ipv4.ProtocolNumber, nil},
} {
t.Run(test.name, func(t *testing.T) {
@@ -294,7 +294,7 @@ func TestBindToDeviceDistribution(t *testing.T) {
defer wq.EventUnregister(&we)
defer close(ch)
- var err *tcpip.Error
+ var err tcpip.Error
ep, err := c.s.NewEndpoint(udp.ProtocolNumber, netProtoNum, &wq)
if err != nil {
t.Fatalf("NewEndpoint failed: %s", err)
diff --git a/pkg/tcpip/stack/transport_test.go b/pkg/tcpip/stack/transport_test.go
index c49427c4c..bebf4e6b5 100644
--- a/pkg/tcpip/stack/transport_test.go
+++ b/pkg/tcpip/stack/transport_test.go
@@ -87,18 +87,18 @@ func (*fakeTransportEndpoint) Readiness(mask waiter.EventMask) waiter.EventMask
return mask
}
-func (*fakeTransportEndpoint) Read(io.Writer, tcpip.ReadOptions) (tcpip.ReadResult, *tcpip.Error) {
+func (*fakeTransportEndpoint) Read(io.Writer, tcpip.ReadOptions) (tcpip.ReadResult, tcpip.Error) {
return tcpip.ReadResult{}, nil
}
-func (f *fakeTransportEndpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, *tcpip.Error) {
+func (f *fakeTransportEndpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcpip.Error) {
if len(f.route.RemoteAddress) == 0 {
- return 0, tcpip.ErrNoRoute
+ return 0, &tcpip.ErrNoRoute{}
}
v := make([]byte, p.Len())
if _, err := io.ReadFull(p, v); err != nil {
- return 0, tcpip.ErrBadBuffer
+ return 0, &tcpip.ErrBadBuffer{}
}
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
@@ -114,37 +114,37 @@ func (f *fakeTransportEndpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions
}
// SetSockOpt sets a socket option. Currently not supported.
-func (*fakeTransportEndpoint) SetSockOpt(tcpip.SettableSocketOption) *tcpip.Error {
- return tcpip.ErrInvalidEndpointState
+func (*fakeTransportEndpoint) SetSockOpt(tcpip.SettableSocketOption) tcpip.Error {
+ return &tcpip.ErrInvalidEndpointState{}
}
// SetSockOptInt sets a socket option. Currently not supported.
-func (*fakeTransportEndpoint) SetSockOptInt(tcpip.SockOptInt, int) *tcpip.Error {
- return tcpip.ErrInvalidEndpointState
+func (*fakeTransportEndpoint) SetSockOptInt(tcpip.SockOptInt, int) tcpip.Error {
+ return &tcpip.ErrInvalidEndpointState{}
}
// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.
-func (*fakeTransportEndpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
- return -1, tcpip.ErrUnknownProtocolOption
+func (*fakeTransportEndpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) {
+ return -1, &tcpip.ErrUnknownProtocolOption{}
}
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
-func (*fakeTransportEndpoint) GetSockOpt(tcpip.GettableSocketOption) *tcpip.Error {
- return tcpip.ErrInvalidEndpointState
+func (*fakeTransportEndpoint) GetSockOpt(tcpip.GettableSocketOption) tcpip.Error {
+ return &tcpip.ErrInvalidEndpointState{}
}
// Disconnect implements tcpip.Endpoint.Disconnect.
-func (*fakeTransportEndpoint) Disconnect() *tcpip.Error {
- return tcpip.ErrNotSupported
+func (*fakeTransportEndpoint) Disconnect() tcpip.Error {
+ return &tcpip.ErrNotSupported{}
}
-func (f *fakeTransportEndpoint) Connect(addr tcpip.FullAddress) *tcpip.Error {
+func (f *fakeTransportEndpoint) Connect(addr tcpip.FullAddress) tcpip.Error {
f.peerAddr = addr.Addr
// Find the route.
r, err := f.proto.stack.FindRoute(addr.NIC, "", addr.Addr, fakeNetNumber, false /* multicastLoop */)
if err != nil {
- return tcpip.ErrNoRoute
+ return &tcpip.ErrNoRoute{}
}
// Try to register so that we can start receiving packets.
@@ -164,22 +164,22 @@ func (f *fakeTransportEndpoint) UniqueID() uint64 {
return f.uniqueID
}
-func (*fakeTransportEndpoint) ConnectEndpoint(e tcpip.Endpoint) *tcpip.Error {
+func (*fakeTransportEndpoint) ConnectEndpoint(e tcpip.Endpoint) tcpip.Error {
return nil
}
-func (*fakeTransportEndpoint) Shutdown(tcpip.ShutdownFlags) *tcpip.Error {
+func (*fakeTransportEndpoint) Shutdown(tcpip.ShutdownFlags) tcpip.Error {
return nil
}
func (*fakeTransportEndpoint) Reset() {
}
-func (*fakeTransportEndpoint) Listen(int) *tcpip.Error {
+func (*fakeTransportEndpoint) Listen(int) tcpip.Error {
return nil
}
-func (f *fakeTransportEndpoint) Accept(*tcpip.FullAddress) (tcpip.Endpoint, *waiter.Queue, *tcpip.Error) {
+func (f *fakeTransportEndpoint) Accept(*tcpip.FullAddress) (tcpip.Endpoint, *waiter.Queue, tcpip.Error) {
if len(f.acceptQueue) == 0 {
return nil, nil, nil
}
@@ -188,7 +188,7 @@ func (f *fakeTransportEndpoint) Accept(*tcpip.FullAddress) (tcpip.Endpoint, *wai
return a, nil, nil
}
-func (f *fakeTransportEndpoint) Bind(a tcpip.FullAddress) *tcpip.Error {
+func (f *fakeTransportEndpoint) Bind(a tcpip.FullAddress) tcpip.Error {
if err := f.proto.stack.RegisterTransportEndpoint(
[]tcpip.NetworkProtocolNumber{fakeNetNumber},
fakeTransNumber,
@@ -203,11 +203,11 @@ func (f *fakeTransportEndpoint) Bind(a tcpip.FullAddress) *tcpip.Error {
return nil
}
-func (*fakeTransportEndpoint) GetLocalAddress() (tcpip.FullAddress, *tcpip.Error) {
+func (*fakeTransportEndpoint) GetLocalAddress() (tcpip.FullAddress, tcpip.Error) {
return tcpip.FullAddress{}, nil
}
-func (*fakeTransportEndpoint) GetRemoteAddress() (tcpip.FullAddress, *tcpip.Error) {
+func (*fakeTransportEndpoint) GetRemoteAddress() (tcpip.FullAddress, tcpip.Error) {
return tcpip.FullAddress{}, nil
}
@@ -237,7 +237,7 @@ func (f *fakeTransportEndpoint) HandlePacket(id stack.TransportEndpointID, pkt *
f.acceptQueue = append(f.acceptQueue, ep)
}
-func (f *fakeTransportEndpoint) HandleControlPacket(stack.ControlType, uint32, *stack.PacketBuffer) {
+func (f *fakeTransportEndpoint) HandleError(stack.TransportError, *stack.PacketBuffer) {
// Increment the number of received control packets.
f.proto.controlCount++
}
@@ -252,7 +252,7 @@ func (*fakeTransportEndpoint) Resume(*stack.Stack) {}
func (*fakeTransportEndpoint) Wait() {}
-func (*fakeTransportEndpoint) LastError() *tcpip.Error {
+func (*fakeTransportEndpoint) LastError() tcpip.Error {
return nil
}
@@ -280,19 +280,19 @@ func (*fakeTransportProtocol) Number() tcpip.TransportProtocolNumber {
return fakeTransNumber
}
-func (f *fakeTransportProtocol) NewEndpoint(netProto tcpip.NetworkProtocolNumber, _ *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
+func (f *fakeTransportProtocol) NewEndpoint(netProto tcpip.NetworkProtocolNumber, _ *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
return newFakeTransportEndpoint(f, netProto, f.stack), nil
}
-func (*fakeTransportProtocol) NewRawEndpoint(tcpip.NetworkProtocolNumber, *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
- return nil, tcpip.ErrUnknownProtocol
+func (*fakeTransportProtocol) NewRawEndpoint(tcpip.NetworkProtocolNumber, *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
+ return nil, &tcpip.ErrUnknownProtocol{}
}
func (*fakeTransportProtocol) MinimumPacketSize() int {
return fakeTransHeaderLen
}
-func (*fakeTransportProtocol) ParsePorts(buffer.View) (src, dst uint16, err *tcpip.Error) {
+func (*fakeTransportProtocol) ParsePorts(buffer.View) (src, dst uint16, err tcpip.Error) {
return 0, 0, nil
}
@@ -300,23 +300,23 @@ func (*fakeTransportProtocol) HandleUnknownDestinationPacket(stack.TransportEndp
return stack.UnknownDestinationPacketHandled
}
-func (f *fakeTransportProtocol) SetOption(option tcpip.SettableTransportProtocolOption) *tcpip.Error {
+func (f *fakeTransportProtocol) SetOption(option tcpip.SettableTransportProtocolOption) tcpip.Error {
switch v := option.(type) {
case *tcpip.TCPModerateReceiveBufferOption:
f.opts.good = bool(*v)
return nil
default:
- return tcpip.ErrUnknownProtocolOption
+ return &tcpip.ErrUnknownProtocolOption{}
}
}
-func (f *fakeTransportProtocol) Option(option tcpip.GettableTransportProtocolOption) *tcpip.Error {
+func (f *fakeTransportProtocol) Option(option tcpip.GettableTransportProtocolOption) tcpip.Error {
switch v := option.(type) {
case *tcpip.TCPModerateReceiveBufferOption:
*v = tcpip.TCPModerateReceiveBufferOption(f.opts.good)
return nil
default:
- return tcpip.ErrUnknownProtocolOption
+ return &tcpip.ErrUnknownProtocolOption{}
}
}