7fc29c1435
Aside from unconditionally unlocking the OS thread even if restoring the thread's network namespace fails, func (*networkNamespace).InvokeFunc() correctly implements invoking a function inside a network namespace. This is far from obvious, however. func InitOSContext() does much of the heavy lifting but in a bizarre fashion: it restores the initial network namespace before it is changed in the first place, and the cleanup function it returns does not restore the network namespace at all! The InvokeFunc() implementation has to restore the network namespace explicitly by deferring a call to ns.SetNamespace(). func InitOSContext() is a leaky abstraction taped to a footgun. On the one hand, it defensively resets the current thread's network namespace, which has the potential to fix up the thread state if other buggy code had failed to maintain the invariant that an OS thread must be locked to a goroutine unless it is interchangeable with a "clean" thread as spawned by the Go runtime. On the other hand, it _facilitates_ writing buggy code which fails to maintain the aforementioned invariant because the cleanup function it returns unlocks the thread from the goroutine unconditionally while neglecting to restore the thread's network namespace! It is quite scary to need a function which fixes up threads' network namespaces after the fact as an arbitrary number of goroutines could have been scheduled onto a "dirty" thread and run non-libnetwork code before the thread's namespace is fixed up. Any number of (not-so-)subtle misbehaviours could result if an unfortunate goroutine is scheduled onto a "dirty" thread. The whole repository has been audited to ensure that the aforementioned invariant is never violated, making after-the-fact fixing up of thread network namespaces redundant. Make InitOSContext() a no-op on Linux and inline the thread-locking into the function (singular) which previously relied on it to do so. func ns.SetNamespace() is of similarly dubious utility. It intermixes capturing the initial network namespace and restoring the thread's network namespace, which could result in threads getting put into the wrong network namespace if the wrong thread is the first to call it. Delete it entirely; functions which need to manipulate a thread's network namespace are better served by being explicit about capturing and restoring the thread's namespace. Rewrite InvokeFunc() to invoke the closure inside a goroutine to enable a graceful and safe recovery if the thread's network namespace could not be restored. Avoid any potential race conditions due to changing the main thread's network namespace by preventing the aforementioned goroutines from being eligible to be scheduled onto the main thread. Signed-off-by: Cory Snider <csnider@mirantis.com> |
||
---|---|---|
.. | ||
init_linux.go | ||
init_windows.go |