summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/stack
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/stack')
-rw-r--r--pkg/tcpip/stack/pending_packets.go2
-rw-r--r--pkg/tcpip/stack/route.go44
2 files changed, 35 insertions, 11 deletions
diff --git a/pkg/tcpip/stack/pending_packets.go b/pkg/tcpip/stack/pending_packets.go
index 22dfc7960..c4769b17e 100644
--- a/pkg/tcpip/stack/pending_packets.go
+++ b/pkg/tcpip/stack/pending_packets.go
@@ -145,7 +145,7 @@ 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)
+ routeInfo, ch, err := r.resolvedFields(nil)
switch err {
case nil:
// The route resolved immediately, so we don't need to wait for link
diff --git a/pkg/tcpip/stack/route.go b/pkg/tcpip/stack/route.go
index 4523e4746..d9a8554e2 100644
--- a/pkg/tcpip/stack/route.go
+++ b/pkg/tcpip/stack/route.go
@@ -315,23 +315,42 @@ func (r *Route) ResolveWith(addr tcpip.LinkAddress) {
r.mu.remoteLinkAddress = addr
}
-// ResolvedFields is like Fields but also attempts to resolve the remote link
-// address if it is not yet known.
+// ResolvedFieldsResult is the result of a route resolution attempt.
+type ResolvedFieldsResult struct {
+ RouteInfo RouteInfo
+ Success bool
+}
+
+// ResolvedFields attempts to resolve the remote link address if it is not
+// known.
//
-// If address resolution is required, returns tcpip.ErrWouldBlock and a
-// notification channel for the caller to block on. The channel will be readable
-// once address resolution is complete (successful or not). If a callback is
-// provided, it will be called when address resolution is complete, regardless
-// of success or failure before the notification channel is readable.
+// If a callback is provided, it will be called before ResolvedFields returns
+// when address resolution is not required. If address resolution is required,
+// the callback will be called once address resolution is complete, regardless
+// of success or failure.
//
// Note, the route will not cache the remote link address when address
// resolution completes.
-func (r *Route) ResolvedFields(afterResolve func()) (RouteInfo, <-chan struct{}, *tcpip.Error) {
+func (r *Route) ResolvedFields(afterResolve func(ResolvedFieldsResult)) *tcpip.Error {
+ _, _, err := r.resolvedFields(afterResolve)
+ return err
+}
+
+// resolvedFields is like ResolvedFields but also returns a notification channel
+// when address resolution is required. This channel will become readable once
+// address resolution is complete.
+//
+// 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) {
r.mu.RLock()
fields := r.fieldsLocked()
resolutionRequired := r.isResolutionRequiredRLocked()
r.mu.RUnlock()
if !resolutionRequired {
+ if afterResolve != nil {
+ afterResolve(ResolvedFieldsResult{RouteInfo: fields, Success: true})
+ }
return fields, nil, nil
}
@@ -347,9 +366,14 @@ func (r *Route) ResolvedFields(afterResolve func()) (RouteInfo, <-chan struct{},
linkAddressResolutionRequestLocalAddr = r.LocalAddress
}
- linkAddr, ch, err := r.outgoingNIC.getNeighborLinkAddress(nextAddr, linkAddressResolutionRequestLocalAddr, r.linkRes, func(LinkResolutionResult) {
+ afterResolveFields := fields
+ linkAddr, ch, err := r.outgoingNIC.getNeighborLinkAddress(nextAddr, linkAddressResolutionRequestLocalAddr, r.linkRes, func(r LinkResolutionResult) {
if afterResolve != nil {
- afterResolve()
+ if r.Success {
+ afterResolveFields.RemoteLinkAddress = r.LinkAddress
+ }
+
+ afterResolve(ResolvedFieldsResult{RouteInfo: afterResolveFields, Success: r.Success})
}
})
if err == nil {