Browse Source

Fix watchMiss thread context

The netlink deserialize is fetching information from the link.
This require the go routine to be in the correct namespace to
succeed

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>
Flavio Crisciani 7 years ago
parent
commit
e975f3caa0

+ 18 - 2
libnetwork/drivers/overlay/ov_network.go

@@ -711,7 +711,7 @@ func (n *network) initSandbox(restore bool) error {
 	n.setNetlinkSocket(nlSock)
 
 	if err == nil {
-		go n.watchMiss(nlSock)
+		go n.watchMiss(nlSock, key)
 	} else {
 		logrus.Errorf("failed to subscribe to neighbor group netlink messages for overlay network %s in sbox %s: %v",
 			n.id, sbox.Key(), err)
@@ -720,7 +720,23 @@ func (n *network) initSandbox(restore bool) error {
 	return nil
 }
 
-func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
+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()
+	newNs, err := netns.GetFromPath(nsPath)
+	if err != nil {
+		logrus.WithError(err).Errorf("failed to get the namespace %s", nsPath)
+		return
+	}
+	defer newNs.Close()
+	if err = netns.Set(newNs); err != nil {
+		logrus.WithError(err).Errorf("failed to enter the namespace %s", nsPath)
+		return
+	}
 	for {
 		msgs, err := nlSock.Receive()
 		if err != nil {

+ 3 - 1
libnetwork/drivers/overlay/overlay_test.go

@@ -2,7 +2,9 @@ package overlay
 
 import (
 	"context"
+	"fmt"
 	"net"
+	"os"
 	"syscall"
 	"testing"
 	"time"
@@ -158,7 +160,7 @@ func TestNetlinkSocket(t *testing.T) {
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	defer cancel()
 	go func() {
-		n.watchMiss(nlSock)
+		n.watchMiss(nlSock, fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
 		ch <- nil
 	}()
 	time.Sleep(5 * time.Second)