libnet/d/overlay: restore thread netns
func (*network) watchMiss() correctly locks its goroutine to an OS thread before changing the thread's network namespace, but neglects to restore the thread's network namespace before unlocking. Fix this oversight by unlocking iff the thread's network namespace is successfully restored. Prevent the watchMiss goroutine from being locked to the main thread to avoid the issues which would arise if such a situation was to occur. Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
parent
3e2f0c7a39
commit
d1e3705c1a
1 changed files with 28 additions and 4 deletions
|
@ -76,6 +76,14 @@ type network struct {
|
|||
|
||||
func init() {
|
||||
reexec.Register("set-default-vlan", setDefaultVlan)
|
||||
|
||||
// Lock main() to the initial thread to exclude the goroutines executing
|
||||
// func (*network).watchMiss() from being scheduled onto that thread.
|
||||
// Changes to the network namespace of the initial thread alter
|
||||
// /proc/self/ns/net, which would break any code which (incorrectly)
|
||||
// assumes that that file is a handle to the network namespace for the
|
||||
// thread it is currently executing on.
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
func setDefaultVlan() {
|
||||
|
@ -779,20 +787,36 @@ func (n *network) initSandbox(restore bool) error {
|
|||
func (n *network) watchMiss(nlSock *nl.NetlinkSocket, nsPath string) {
|
||||
// With the new version of the netlink library the deserialize function makes
|
||||
// requests about the interface of the netlink message. This can succeed only
|
||||
// if this go routine is in the target namespace. For this reason following we
|
||||
// lock the thread on that namespace
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
// if this go routine is in the target namespace.
|
||||
origNs, err := netns.Get()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("failed to get the initial network namespace")
|
||||
return
|
||||
}
|
||||
defer origNs.Close()
|
||||
newNs, err := netns.GetFromPath(nsPath)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Errorf("failed to get the namespace %s", nsPath)
|
||||
return
|
||||
}
|
||||
defer newNs.Close()
|
||||
|
||||
runtime.LockOSThread()
|
||||
if err = netns.Set(newNs); err != nil {
|
||||
logrus.WithError(err).Errorf("failed to enter the namespace %s", nsPath)
|
||||
runtime.UnlockOSThread()
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err := netns.Set(origNs); err != nil {
|
||||
logrus.WithError(err).Error("failed to restore the thread's initial network namespace")
|
||||
// The error is only fatal for the current thread. Keep this
|
||||
// goroutine locked to the thread to make the runtime replace it
|
||||
// with a clean thread once this goroutine terminates.
|
||||
} else {
|
||||
runtime.UnlockOSThread()
|
||||
}
|
||||
}()
|
||||
for {
|
||||
msgs, _, err := nlSock.Receive()
|
||||
if err != nil {
|
||||
|
|
Loading…
Add table
Reference in a new issue