-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discussion: removing lockThread from WithNetNS? #183
Comments
Any chance we could postpone any PR from here until I've gotten #167 merged? That changes quite a few things in the NS package so that we can mock out namespace operations. |
So the current closures take a pointer to the current host netNS, which this proposal drops. Maybe that was an oversight? If so, one issue I see with the current code is that the current netns from the goroutine won't necessarily be the calling thread's namespace that the closure will expect. ptp.go's setupVeth() still uses that to make sure that the host-side is put in the right namespace. That might require grabbing hte current thread's netns twice, once outside the goroutine (to pass to the closure) and once inside (to kindly reset that thread's namespace). |
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
@rosenhouse I've implemented the approach you've outlined here in #167 in the first commit "ns: make namespaces an interface and add NetNS creation capability", and since I moved the NetNS creation capability into the ns package itself the testhelpers stuff goes away (including the testcases, the unique ones I added to ns_test.go). Seems to work pretty well. |
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
@dcbw Thanks for the comments, I'm glad you found this useful already for your PR. Dropping the "host" netNS argument to I would be totally in favor of exporting a function like func CurrentNetNS() (*os.File, error) {
return os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
} to make the closure approach easy, e.g. originalNS := ns.CurrentNetNS()
err := ns.WithNetNS(containerNS, func() error {
// do stuff with containerNS
innerErr := ns.WithNetNS(originalNS, func() error {
/* do stuff in originalNS */
})
if innerErr != nil {
return innerErr
}
// do more stuff in the containerNS
} (And of course Does that make sense? Am I missing a use-case for the function argument? |
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
That makes sense, and I was originally removing the argument until I found the sole caller(s). I'll play around and see what I come up with. |
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
This also removes the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
This issue is even more complicated than I originally thought in the case of nested calls to the For this reason, the code above is dangerous -- specifically my follow-up comment showing nested calls. I'm closing this issue until we can figure out how to make this safer. |
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking/cni#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking/cni#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
…sues Add a namespace object interface for somewhat cleaner code when creating and switching between network namespaces. All created namespaces are now mounted in /var/run/netns to ensure they have persistent inodes and paths that can be passed around between plugin components without relying on the current namespace being correct. Also remove the thread-locking arguments from the ns package per containernetworking/cni#183 by doing all the namespace changes in a separate goroutine that locks/unlocks itself, instead of the caller having to track OS thread locking.
Summary
I believe that we can provide
WithNetNS
andWithNetNSPath
functions that remove thelockThread
argument and completely hide from the caller the complexity of goroutine thread affinity. This could let us simplify a lot of our plugin and test code. I'm opening this issue to gather feedback before I assemble a PR.Background
In our network namespace switching package, we provide
WithNetNS
which runs a function
f
inside a network namespacens
.The middle argument,
lockThread
is easily misused.If the caller passes
false
then she must be sure that she has calledruntime.LockOSThread
beforehand. Many of the CNI plugins use this approach, but it requires care, especially when creating goroutines.Conversely, if the caller passes
true
, then that must be the only call usingtrue
within the call-stack. This is becauseLock
andUnlockOSThread
do not reference count, so a singleUnlock
will unlock all priorLock
calls. That can leave a caller unlocked without knowing it.Incorrect usage either way can lead to all sorts of hard-to-debug undefined behavior as goroutines end up in unexpected namespaces.
Proposed change
Replace
WithNetNS
inpkg/ns
with the followingWe would need to update all uses of
WithNetNS
andWithNetNSPath
to drop thelockThread
boolean.To see this approach in a slightly different context, look at
MakeNetworkNS
in our newtesthelpers
package. There are some explanatory comments above that.Feedback?
Please share why this won't work, would break your client, or other issues you forsee. I haven't looked carefully at all the plugins.
If there aren't objections, I can put together a PR. (I know there are a couple other PRs in flight addressing netns switching and test coverage of plugins, there may be some overlap here? #167 #176 )
Thanks to @zachgersh for the original insight here.
cc: @sykesm
The text was updated successfully, but these errors were encountered: