diff options
-rw-r--r-- | pkg/tcpip/stack/neighbor_cache.go | 2 | ||||
-rw-r--r-- | pkg/tcpip/stack/neighbor_entry.go | 37 | ||||
-rw-r--r-- | pkg/tcpip/stack/nic.go | 2 | ||||
-rw-r--r-- | pkg/tcpip/stack/pending_packets.go | 12 | ||||
-rw-r--r-- | pkg/tcpip/stack/route.go | 8 | ||||
-rw-r--r-- | pkg/tcpip/stack/stack.go | 2 |
6 files changed, 34 insertions, 29 deletions
diff --git a/pkg/tcpip/stack/neighbor_cache.go b/pkg/tcpip/stack/neighbor_cache.go index 6b1f8da86..509f5ce5c 100644 --- a/pkg/tcpip/stack/neighbor_cache.go +++ b/pkg/tcpip/stack/neighbor_cache.go @@ -140,7 +140,7 @@ func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, onResolve fun // a node continues sending packets to that neighbor using the cached // link-layer address." if onResolve != nil { - onResolve(LinkResolutionResult{LinkAddress: entry.mu.neigh.LinkAddr, Success: true}) + onResolve(LinkResolutionResult{LinkAddress: entry.mu.neigh.LinkAddr, Err: nil}) } return entry.mu.neigh, nil, nil case Unknown, Incomplete, Unreachable: diff --git a/pkg/tcpip/stack/neighbor_entry.go b/pkg/tcpip/stack/neighbor_entry.go index 36d3cad62..6d95e1664 100644 --- a/pkg/tcpip/stack/neighbor_entry.go +++ b/pkg/tcpip/stack/neighbor_entry.go @@ -157,8 +157,8 @@ func newStaticNeighborEntry(cache *neighborCache, addr tcpip.Address, linkAddr t // the link address if resolution completed successfully. // // Precondition: e.mu MUST be locked. -func (e *neighborEntry) notifyCompletionLocked(succeeded bool) { - res := LinkResolutionResult{LinkAddress: e.mu.neigh.LinkAddr, Success: succeeded} +func (e *neighborEntry) notifyCompletionLocked(err tcpip.Error) { + res := LinkResolutionResult{LinkAddress: e.mu.neigh.LinkAddr, Err: err} for _, callback := range e.mu.onResolve { callback(res) } @@ -173,7 +173,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.cache.nic.linkResQueue.dequeue(ch, e.mu.neigh.LinkAddr, succeeded) + go e.cache.nic.linkResQueue.dequeue(ch, e.mu.neigh.LinkAddr, err) } } @@ -227,7 +227,13 @@ func (e *neighborEntry) removeLocked() { e.mu.neigh.UpdatedAtNanos = e.cache.nic.stack.clock.NowNanoseconds() e.dispatchRemoveEventLocked() e.cancelTimerLocked() - e.notifyCompletionLocked(false /* succeeded */) + // TODO(https://gvisor.dev/issues/5583): test the case where this function is + // called during resolution; that can happen in at least these scenarios: + // + // - manual address removal during resolution + // + // - neighbor cache eviction during resolution + e.notifyCompletionLocked(&tcpip.ErrAborted{}) } // setStateLocked transitions the entry to the specified state immediately. @@ -302,9 +308,8 @@ func (e *neighborEntry) setStateLocked(next NeighborState) { e.mu.timer = timer{ done: &done, timer: e.cache.nic.stack.Clock().AfterFunc(0, func() { - var err tcpip.Error - timedoutResolution := remaining == 0 - if !timedoutResolution { + var err tcpip.Error = &tcpip.ErrTimeout{} + if remaining != 0 { err = e.cache.linkRes.LinkAddressRequest(addr, "" /* localAddr */, linkAddr) } @@ -316,8 +321,9 @@ func (e *neighborEntry) setStateLocked(next NeighborState) { return } - if timedoutResolution || err != nil { + if err != nil { e.setStateLocked(Unreachable) + e.notifyCompletionLocked(err) e.dispatchChangeEventLocked() return } @@ -328,7 +334,6 @@ func (e *neighborEntry) setStateLocked(next NeighborState) { } case Unreachable: - e.notifyCompletionLocked(false /* succeeded */) case Unknown, Stale, Static: // Do nothing @@ -374,9 +379,8 @@ func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) { e.mu.timer = timer{ done: &done, timer: e.cache.nic.stack.Clock().AfterFunc(0, func() { - var err tcpip.Error - timedoutResolution := remaining == 0 - if !timedoutResolution { + var err tcpip.Error = &tcpip.ErrTimeout{} + if remaining != 0 { // As per RFC 4861 section 7.2.2: // // If the source address of the packet prompting the solicitation is @@ -395,8 +399,9 @@ func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) { return } - if timedoutResolution || err != nil { + if err != nil { e.setStateLocked(Unreachable) + e.notifyCompletionLocked(err) e.dispatchChangeEventLocked() return } @@ -442,7 +447,7 @@ func (e *neighborEntry) handleProbeLocked(remoteLinkAddr tcpip.LinkAddress) { // - RFC 4861 section 7.2.3 e.mu.neigh.LinkAddr = remoteLinkAddr e.setStateLocked(Stale) - e.notifyCompletionLocked(true /* succeeded */) + e.notifyCompletionLocked(nil) e.dispatchChangeEventLocked() case Reachable, Delay, Probe: @@ -504,7 +509,7 @@ func (e *neighborEntry) handleConfirmationLocked(linkAddr tcpip.LinkAddress, fla } e.dispatchChangeEventLocked() e.mu.isRouter = flags.IsRouter - e.notifyCompletionLocked(true /* succeeded */) + e.notifyCompletionLocked(nil) // "Note that the Override flag is ignored if the entry is in the // INCOMPLETE state." - RFC 4861 section 7.2.5 @@ -539,7 +544,7 @@ func (e *neighborEntry) handleConfirmationLocked(linkAddr tcpip.LinkAddress, fla wasReachable := e.mu.neigh.State == Reachable // Set state to Reachable again to refresh timers. e.setStateLocked(Reachable) - e.notifyCompletionLocked(true /* succeeded */) + e.notifyCompletionLocked(nil) if !wasReachable { e.dispatchChangeEventLocked() } diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go index f66db16a7..f9323d545 100644 --- a/pkg/tcpip/stack/nic.go +++ b/pkg/tcpip/stack/nic.go @@ -613,7 +613,7 @@ func (n *nic) getLinkAddress(addr, localAddr tcpip.Address, protocol tcpip.Netwo } if linkAddr, ok := linkRes.resolver.ResolveStaticAddress(addr); ok { - onResolve(LinkResolutionResult{LinkAddress: linkAddr, Success: true}) + onResolve(LinkResolutionResult{LinkAddress: linkAddr, Err: nil}) return nil } diff --git a/pkg/tcpip/stack/pending_packets.go b/pkg/tcpip/stack/pending_packets.go index dc139ebb2..e936aa728 100644 --- a/pkg/tcpip/stack/pending_packets.go +++ b/pkg/tcpip/stack/pending_packets.go @@ -91,9 +91,9 @@ func (f *packetsPendingLinkResolution) init(nic *nic) { // dequeue any pending packets associated with ch. // -// If success is true, packets will be written and sent to the given remote link +// If err is nil, packets will be written and sent to the given remote link // address. -func (f *packetsPendingLinkResolution) dequeue(ch <-chan struct{}, linkAddr tcpip.LinkAddress, success bool) { +func (f *packetsPendingLinkResolution) dequeue(ch <-chan struct{}, linkAddr tcpip.LinkAddress, err tcpip.Error) { f.mu.Lock() packets, ok := f.mu.packets[ch] delete(f.mu.packets, ch) @@ -110,7 +110,7 @@ func (f *packetsPendingLinkResolution) dequeue(ch <-chan struct{}, linkAddr tcpi f.mu.Unlock() if ok { - f.dequeuePackets(packets, linkAddr, success) + f.dequeuePackets(packets, linkAddr, err) } } @@ -176,7 +176,7 @@ func (f *packetsPendingLinkResolution) enqueue(r *Route, gso *GSO, proto tcpip.N if len(cancelledPackets) != 0 { // Dequeue the pending packets in a new goroutine to not hold up the current // goroutine as handing link resolution failures may be a costly operation. - go f.dequeuePackets(cancelledPackets, "" /* linkAddr */, false /* success */) + go f.dequeuePackets(cancelledPackets, "" /* linkAddr */, &tcpip.ErrAborted{}) } return pkt.len(), nil @@ -207,9 +207,9 @@ func (f *packetsPendingLinkResolution) newCancelChannelLocked(newCH <-chan struc return packets } -func (f *packetsPendingLinkResolution) dequeuePackets(packets []pendingPacket, linkAddr tcpip.LinkAddress, success bool) { +func (f *packetsPendingLinkResolution) dequeuePackets(packets []pendingPacket, linkAddr tcpip.LinkAddress, err tcpip.Error) { for _, p := range packets { - if success { + if err == nil { p.routeInfo.RemoteLinkAddress = linkAddr _, _ = f.nic.writePacketBuffer(p.routeInfo, p.gso, p.proto, p.pkt) } else { diff --git a/pkg/tcpip/stack/route.go b/pkg/tcpip/stack/route.go index e946f9fe3..4ba6794a0 100644 --- a/pkg/tcpip/stack/route.go +++ b/pkg/tcpip/stack/route.go @@ -318,7 +318,7 @@ func (r *Route) ResolveWith(addr tcpip.LinkAddress) { // ResolvedFieldsResult is the result of a route resolution attempt. type ResolvedFieldsResult struct { RouteInfo RouteInfo - Success bool + Err tcpip.Error } // ResolvedFields attempts to resolve the remote link address if it is not @@ -349,7 +349,7 @@ func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteIn r.mu.RUnlock() if !resolutionRequired { if afterResolve != nil { - afterResolve(ResolvedFieldsResult{RouteInfo: fields, Success: true}) + afterResolve(ResolvedFieldsResult{RouteInfo: fields, Err: nil}) } return fields, nil, nil } @@ -364,11 +364,11 @@ func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteIn afterResolveFields := fields linkAddr, ch, err := r.linkRes.getNeighborLinkAddress(r.nextHop(), linkAddressResolutionRequestLocalAddr, func(r LinkResolutionResult) { if afterResolve != nil { - if r.Success { + if r.Err == nil { afterResolveFields.RemoteLinkAddress = r.LinkAddress } - afterResolve(ResolvedFieldsResult{RouteInfo: afterResolveFields, Success: r.Success}) + afterResolve(ResolvedFieldsResult{RouteInfo: afterResolveFields, Err: r.Err}) } }) if err == nil { diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index 674c9a1ff..de94ddfda 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -1542,7 +1542,7 @@ func (s *Stack) SetSpoofing(nicID tcpip.NICID, enable bool) tcpip.Error { // LinkResolutionResult is the result of a link address resolution attempt. type LinkResolutionResult struct { LinkAddress tcpip.LinkAddress - Success bool + Err tcpip.Error } // GetLinkAddress finds the link address corresponding to a network address. |