@@ -155,7 +155,7 @@ func (l *magiclink) Swap(fd, mtu int) (err error) {
155155 needsNewEndpoint = errors .Is (err , errNeedsNewEndpoint )
156156 }
157157
158- if ! needsNewEndpoint {
158+ if hasSwappedFd || ! needsNewEndpoint {
159159 logei (! hasSwappedFd )("netstack: magic(%d); swap: ok? %t; err? %v" ,
160160 fd , hasSwappedFd , err )
161161 return err
@@ -173,21 +173,22 @@ func (l *magiclink) Swap(fd, mtu int) (err error) {
173173 return core .OneErr (err , errMissingEp )
174174 }
175175
176- old := l . e . Swap ( ep )
177-
176+ // attach eventually runs a dispatchLoop which kickstarts the endpoint's
177+ // delivery of packets to netstack's dispatcher.
178178 d := l .d .Load ()
179179 if d == nil {
180180 ep .Attach (nil ) // attach the new endpoint to the dispatcher
181181 } else {
182182 ep .Attach (l ) // attach the new endpoint to the existing dispatcher
183183 }
184-
185- // Close the old endpoint after the new one is attached to ensure
186- // proper sequencing and avoid WaitGroup reuse issues
187- if old != nil {
184+
185+ // swap endpoints after the dispatchLoop has had the chance to start
186+ // to avoid cases where clients end up calling ep.Wait() before dispatchLoop
187+ // could begin (as it is responsible for keeping ep alive)
188+ if old := l .e .Swap (ep ); old != nil {
188189 core .Go ("magic." + strconv .Itoa (fd ), old .Close )
189190 }
190-
191+
191192 logei (d == nil )("netstack: magic(%d) mtu: %d; swap: new ep... dispatch? %t" ,
192193 fd , umtu , d != nil )
193194
@@ -313,16 +314,12 @@ func (l *magiclink) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error)
313314}
314315
315316func (l * magiclink ) Wait () {
316- // Atomically load the current endpoint to prevent race conditions
317- // during endpoint swapping. If endpoint is swapped while we're
318- // waiting, we should wait on the endpoint we loaded, not the new one.
319- // This prevents WaitGroup reuse issues.
320- e := l .e .Load ()
321- if e != nil {
322- // Use a recovered call to prevent panics from propagating
323- // in case of WaitGroup reuse issues
324- defer core .Recover (core .Exit11 , "magiclink.wait" )
325- e .Wait ()
317+ if e := l .e .Load (); e != nil {
318+ if e .IsAttached () {
319+ e .Wait () // may panic in case of WaitGroup reuse issues
320+ } else {
321+ log .W ("netstack: magic: wait; dispatcher not attached; has dispatcher? %t" , l .d .Load () != nil )
322+ }
326323 }
327324}
328325
0 commit comments