ipn/ipnlocal,wgengine/magicsock: wait for magicsock to process pending events on authReconfig

Updates #16369

Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
Nick Khyl
2025-06-24 13:39:29 -05:00
committed by Nick Khyl
parent 4a1fc378d1
commit 9e28bfc69c
4 changed files with 95 additions and 1 deletions

View File

@@ -167,6 +167,8 @@ type Conn struct {
filterSub *eventbus.Subscriber[FilterUpdate]
nodeViewsSub *eventbus.Subscriber[NodeViewsUpdate]
nodeMutsSub *eventbus.Subscriber[NodeMutationsUpdate]
syncSub *eventbus.Subscriber[syncPoint]
syncPub *eventbus.Publisher[syncPoint]
subsDoneCh chan struct{} // closed when consumeEventbusTopics returns
// pconn4 and pconn6 are the underlying UDP sockets used to
@@ -538,6 +540,21 @@ type FilterUpdate struct {
*filter.Filter
}
// syncPoint is an event published over an [eventbus.Bus] by [Conn.Synchronize].
// It serves as a synchronization point, allowing to wait until magicsock
// has processed all pending events.
type syncPoint chan struct{}
// Wait blocks until [syncPoint.Signal] is called.
func (s syncPoint) Wait() {
<-s
}
// Signal signals the sync point, unblocking the [syncPoint.Wait] call.
func (s syncPoint) Signal() {
close(s)
}
// newConn is the error-free, network-listening-side-effect-free based
// of NewConn. Mostly for tests.
func newConn(logf logger.Logf) *Conn {
@@ -593,10 +610,25 @@ func (c *Conn) consumeEventbusTopics() {
c.onNodeViewsUpdate(nodeViews)
case nodeMuts := <-c.nodeMutsSub.Events():
c.onNodeMutationsUpdate(nodeMuts)
case syncPoint := <-c.syncSub.Events():
c.dlogf("magicsock: received sync point after reconfig")
syncPoint.Signal()
}
}
}
// Synchronize waits for all [eventbus] events published
// prior to this call to be processed by the receiver.
func (c *Conn) Synchronize() {
if c.syncPub == nil {
// Eventbus is not used; no need to synchronize (in certain tests).
return
}
sp := syncPoint(make(chan struct{}))
c.syncPub.Publish(sp)
sp.Wait()
}
// NewConn creates a magic Conn listening on opts.Port.
// As the set of possible endpoints for a Conn changes, the
// callback opts.EndpointsFunc is called.
@@ -624,6 +656,8 @@ func NewConn(opts Options) (*Conn, error) {
c.filterSub = eventbus.Subscribe[FilterUpdate](c.eventClient)
c.nodeViewsSub = eventbus.Subscribe[NodeViewsUpdate](c.eventClient)
c.nodeMutsSub = eventbus.Subscribe[NodeMutationsUpdate](c.eventClient)
c.syncSub = eventbus.Subscribe[syncPoint](c.eventClient)
c.syncPub = eventbus.Publish[syncPoint](c.eventClient)
c.subsDoneCh = make(chan struct{})
go c.consumeEventbusTopics()
}