From db7acd8b14194b4d801c62cbf9d99fabcb0bb7a7 Mon Sep 17 00:00:00 2001 From: Quan Tian Date: Sat, 22 Aug 2020 01:34:38 +0800 Subject: [PATCH] Fix race condition in GetCurrentNS temporarily (#1131) In GetCurrentNS, If there is a context-switch between getCurrentThreadNetNSPath and GetNS, another goroutine may execute in the original thread and change its network namespace, then the original goroutine would get the updated network namespace, which could lead to unexpected behavior, especially when GetCurrentNS is used to get the host network namespace in netNS.Do. Instead of using the provided netns argument, this patch fixes it by getting the hostNS in advance with the OS thread locked. --- .../cniserver/interface_configuration_linux.go | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pkg/agent/cniserver/interface_configuration_linux.go b/pkg/agent/cniserver/interface_configuration_linux.go index b22877fa9f4..ff413a3620e 100644 --- a/pkg/agent/cniserver/interface_configuration_linux.go +++ b/pkg/agent/cniserver/interface_configuration_linux.go @@ -19,6 +19,7 @@ package cniserver import ( "fmt" "net" + "runtime" "time" "github.com/Mellanox/sriovnet" @@ -194,7 +195,22 @@ func (ic *ifConfigurator) configureContainerLinkVeth( hostIface := ¤t.Interface{Name: hostIfaceName} containerIface := ¤t.Interface{Name: containerIfaceName, Sandbox: containerNetNS} result.Interfaces = []*current.Interface{hostIface, containerIface} - if err := ns.WithNetNSPath(containerNetNS, func(hostNS ns.NetNS) error { + + // This is a workaround for issue #1113, which is caused by https://github.com/containernetworking/plugins/issues/524. + // Instead of using the provided netns argument, which might not be the real hostNS, it fixes it by getting the + // hostNS in advance with the OS thread locked. + // TODO: remove this once the upstream issue is fixed. + hostNS, err := func() (ns.NetNS, error) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + return ns.GetCurrentNS() + }() + if err != nil { + return fmt.Errorf("failed to get host netns: %v", err) + } + defer hostNS.Close() + + if err := ns.WithNetNSPath(containerNetNS, func(_ ns.NetNS) error { klog.V(2).Infof("Creating veth devices (%s, %s) for container %s", containerIfaceName, hostIfaceName, containerID) hostVeth, containerVeth, err := ip.SetupVethWithName(containerIfaceName, hostIfaceName, mtu, hostNS) if err != nil {