@@ -155,7 +155,7 @@ func (l *magiclink) Swap(fd, mtu int) (err error) {
155
155
needsNewEndpoint = errors .Is (err , errNeedsNewEndpoint )
156
156
}
157
157
158
- if ! needsNewEndpoint {
158
+ if hasSwappedFd || ! needsNewEndpoint {
159
159
logei (! hasSwappedFd )("netstack: magic(%d); swap: ok? %t; err? %v" ,
160
160
fd , hasSwappedFd , err )
161
161
return err
@@ -173,21 +173,22 @@ func (l *magiclink) Swap(fd, mtu int) (err error) {
173
173
return core .OneErr (err , errMissingEp )
174
174
}
175
175
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.
178
178
d := l .d .Load ()
179
179
if d == nil {
180
180
ep .Attach (nil ) // attach the new endpoint to the dispatcher
181
181
} else {
182
182
ep .Attach (l ) // attach the new endpoint to the existing dispatcher
183
183
}
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 {
188
189
core .Go ("magic." + strconv .Itoa (fd ), old .Close )
189
190
}
190
-
191
+
191
192
logei (d == nil )("netstack: magic(%d) mtu: %d; swap: new ep... dispatch? %t" ,
192
193
fd , umtu , d != nil )
193
194
@@ -313,16 +314,12 @@ func (l *magiclink) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error)
313
314
}
314
315
315
316
func (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
+ }
326
323
}
327
324
}
328
325
0 commit comments