mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Correctly lock when removing neighbor entries
Fix a panic when two entries in Failed state are removed at the same time. PiperOrigin-RevId: 344143777
This commit is contained in:
@@ -233,6 +233,8 @@ func (n *neighborCache) addStaticEntry(addr tcpip.Address, linkAddr tcpip.LinkAd
|
||||
}
|
||||
|
||||
// removeEntryLocked removes the specified entry from the neighbor cache.
|
||||
//
|
||||
// Prerequisite: n.mu and entry.mu MUST be locked.
|
||||
func (n *neighborCache) removeEntryLocked(entry *neighborEntry) {
|
||||
if entry.neigh.State != Static {
|
||||
n.dynamic.lru.Remove(entry)
|
||||
|
||||
@@ -80,7 +80,7 @@ func entryDiffOptsWithSort() []cmp.Option {
|
||||
func newTestNeighborCache(nudDisp NUDDispatcher, config NUDConfigurations, clock tcpip.Clock) *neighborCache {
|
||||
config.resetInvalidFields()
|
||||
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
return &neighborCache{
|
||||
neigh := &neighborCache{
|
||||
nic: &NIC{
|
||||
stack: &Stack{
|
||||
clock: clock,
|
||||
@@ -92,6 +92,8 @@ func newTestNeighborCache(nudDisp NUDDispatcher, config NUDConfigurations, clock
|
||||
state: NewNUDState(config, rng),
|
||||
cache: make(map[tcpip.Address]*neighborEntry, neighborCacheSize),
|
||||
}
|
||||
neigh.nic.neigh = neigh
|
||||
return neigh
|
||||
}
|
||||
|
||||
// testEntryStore contains a set of IP to NeighborEntry mappings.
|
||||
|
||||
@@ -258,7 +258,7 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
|
||||
|
||||
case Failed:
|
||||
e.notifyWakersLocked()
|
||||
e.job = e.nic.stack.newJob(&e.mu, func() {
|
||||
e.job = e.nic.stack.newJob(&doubleLock{first: &e.nic.neigh.mu, second: &e.mu}, func() {
|
||||
e.nic.neigh.removeEntryLocked(e)
|
||||
})
|
||||
e.job.Schedule(config.UnreachableTime)
|
||||
@@ -512,3 +512,23 @@ func (e *neighborEntry) handleUpperLevelConfirmationLocked() {
|
||||
panic(fmt.Sprintf("Invalid cache entry state: %s", e.neigh.State))
|
||||
}
|
||||
}
|
||||
|
||||
// doubleLock combines two locks into one while maintaining lock ordering.
|
||||
//
|
||||
// TODO(gvisor.dev/issue/4796): Remove this once subsequent traffic to a Failed
|
||||
// neighbor is allowed.
|
||||
type doubleLock struct {
|
||||
first, second sync.Locker
|
||||
}
|
||||
|
||||
// Lock locks both locks in order: first then second.
|
||||
func (l *doubleLock) Lock() {
|
||||
l.first.Lock()
|
||||
l.second.Lock()
|
||||
}
|
||||
|
||||
// Unlock unlocks both locks in reverse order: second then first.
|
||||
func (l *doubleLock) Unlock() {
|
||||
l.second.Unlock()
|
||||
l.first.Unlock()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user