summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/stack/linkaddrcache.go
diff options
context:
space:
mode:
authorGhanan Gowripalan <ghanan@google.com>2021-01-21 16:37:35 -0800
committergVisor bot <gvisor-bot@google.com>2021-01-21 16:40:06 -0800
commit8ecff1890277820972c5f5287539a824b22a1d60 (patch)
tree5c3b3473dfa825feffee79ae1b47eda1a9e22c2b /pkg/tcpip/stack/linkaddrcache.go
parent48dfb8db9e784604e9c7ad8e1a36cc862dac1b4d (diff)
Do not cache remote link address in Route
...unless explicitly requested via ResolveWith. Remove cancelled channels from pending packets as we can use the link resolution channel in a FIFO to limit the number of maximum pending resolutions we should queue packets for. This change also defers starting the goroutine that handles link resolution completion to when link resolution succeeds, fails or gets cancelled due to the max number of pending resolutions being reached. Fixes #751. PiperOrigin-RevId: 353130577
Diffstat (limited to 'pkg/tcpip/stack/linkaddrcache.go')
-rw-r--r--pkg/tcpip/stack/linkaddrcache.go20
1 files changed, 17 insertions, 3 deletions
diff --git a/pkg/tcpip/stack/linkaddrcache.go b/pkg/tcpip/stack/linkaddrcache.go
index 3c4fa341e..f116f8417 100644
--- a/pkg/tcpip/stack/linkaddrcache.go
+++ b/pkg/tcpip/stack/linkaddrcache.go
@@ -32,6 +32,8 @@ var _ LinkAddressCache = (*linkAddrCache)(nil)
//
// This struct is safe for concurrent use.
type linkAddrCache struct {
+ nic *NIC
+
// ageLimit is how long a cache entry is valid for.
ageLimit time.Duration
@@ -79,6 +81,8 @@ type linkAddrEntry struct {
// linkAddrEntryEntry access is synchronized by the linkAddrCache lock.
linkAddrEntryEntry
+ cache *linkAddrCache
+
// TODO(gvisor.dev/issue/5150): move these fields under mu.
// mu protects the fields below.
mu sync.RWMutex
@@ -104,6 +108,14 @@ func (e *linkAddrEntry) notifyCompletionLocked(linkAddr tcpip.LinkAddress) {
if ch := e.done; ch != nil {
close(ch)
e.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.
+ //
+ // At the time of writing, when writing packets, a neighbor's link address
+ // 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, linkAddr, len(linkAddr) != 0)
}
}
@@ -174,8 +186,9 @@ func (c *linkAddrCache) getOrCreateEntryLocked(k tcpip.Address) *linkAddrEntry {
}
*entry = linkAddrEntry{
- addr: k,
- s: incomplete,
+ cache: c,
+ addr: k,
+ s: incomplete,
}
c.cache.table[k] = entry
c.cache.lru.PushFront(entry)
@@ -264,8 +277,9 @@ func (c *linkAddrCache) checkLinkRequest(now time.Time, k tcpip.Address, attempt
return true
}
-func newLinkAddrCache(ageLimit, resolutionTimeout time.Duration, resolutionAttempts int) *linkAddrCache {
+func newLinkAddrCache(nic *NIC, ageLimit, resolutionTimeout time.Duration, resolutionAttempts int) *linkAddrCache {
c := &linkAddrCache{
+ nic: nic,
ageLimit: ageLimit,
resolutionTimeout: resolutionTimeout,
resolutionAttempts: resolutionAttempts,