Skip to content

Commit 812dfce

Browse files
authored
pan: fix missing mutex in path refresher (#215)
The subscribers map needs to be protected by a mutex, otherwise this map may be concurrently modified. To avoid overly long locks while refreshing, which would globally block dialing or closing connections, the lock is not held during the actual path query.
1 parent d4d0424 commit 812dfce

File tree

1 file changed

+21
-5
lines changed

1 file changed

+21
-5
lines changed

pkg/pan/refresher.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package pan
1717
import (
1818
"context"
1919
"math/rand"
20+
"sync"
2021
"time"
2122
)
2223

@@ -25,9 +26,10 @@ type refreshee interface {
2526
}
2627

2728
type refresher struct {
28-
subscribers map[IA][]refreshee
29-
pool *pathPool
30-
newSubscription chan bool
29+
subscribersMutex sync.Mutex
30+
subscribers map[IA][]refreshee
31+
newSubscription chan bool
32+
pool *pathPool
3133
}
3234

3335
func makeRefresher(pool *pathPool) refresher {
@@ -48,6 +50,8 @@ func (r *refresher) subscribe(ctx context.Context, dst IA, s refreshee) ([]*Path
4850
if len(paths) == 0 {
4951
return nil, errNoPathTo(dst)
5052
}
53+
r.subscribersMutex.Lock()
54+
defer r.subscribersMutex.Unlock()
5155
subs, ok := r.subscribers[dst]
5256
r.subscribers[dst] = append(subs, s)
5357
if !ok {
@@ -57,6 +61,9 @@ func (r *refresher) subscribe(ctx context.Context, dst IA, s refreshee) ([]*Path
5761
}
5862

5963
func (r *refresher) unsubscribe(ia IA, s refreshee) {
64+
r.subscribersMutex.Lock()
65+
defer r.subscribersMutex.Unlock()
66+
6067
idx := -1
6168
subs := r.subscribers[ia]
6269
for i, v := range subs {
@@ -100,7 +107,14 @@ func (r *refresher) run() {
100107
func (r *refresher) refresh() {
101108
now := time.Now()
102109
// when a refresh is triggered, we batch all
103-
for dstIA, subscribers := range r.subscribers {
110+
r.subscribersMutex.Lock()
111+
refreshIAs := make([]IA, 0, len(r.subscribers))
112+
for dstIA := range r.subscribers {
113+
refreshIAs = append(refreshIAs, dstIA)
114+
}
115+
r.subscribersMutex.Unlock()
116+
117+
for _, dstIA := range refreshIAs {
104118
poolEntry, _ := r.pool.entry(dstIA)
105119
if r.shouldRefresh(now, poolEntry.earliestExpiry, poolEntry.lastQuery) {
106120
paths, err := r.pool.queryPaths(context.Background(), dstIA)
@@ -112,9 +126,11 @@ func (r *refresher) refresh() {
112126
// to sciond or something like that.
113127
continue
114128
}
115-
for _, subscriber := range subscribers {
129+
r.subscribersMutex.Lock()
130+
for _, subscriber := range r.subscribers[dstIA] {
116131
subscriber.refresh(dstIA, paths)
117132
}
133+
r.subscribersMutex.Unlock()
118134
}
119135
}
120136
}

0 commit comments

Comments
 (0)