Go Linux网络名称空间意外行为
所以我最近一直在玩弄网络名称空间。 我编写了一个简单的代码,构建了它,并注意到发生了一些非常奇怪的事情 代码如下:Go Linux网络名称空间意外行为,go,linux-kernel,kernel,ubuntu-14.04,linux-namespaces,Go,Linux Kernel,Kernel,Ubuntu 14.04,Linux Namespaces,所以我最近一直在玩弄网络名称空间。 我编写了一个简单的代码,构建了它,并注意到发生了一些非常奇怪的事情 代码如下: package main import ( "fmt" "log" "net" "os" "path" "syscall" ) const ( NsRunDir = "/var/run/netns" SelfNetNs = "/proc/self/ns/net" ) func main() { netN
package main
import (
"fmt"
"log"
"net"
"os"
"path"
"syscall"
)
const (
NsRunDir = "/var/run/netns"
SelfNetNs = "/proc/self/ns/net"
)
func main() {
netNsPath := path.Join(NsRunDir, "myns")
os.Mkdir(NsRunDir, 0755)
if err := syscall.Mount(NsRunDir, NsRunDir, "none", syscall.MS_BIND, ""); err != nil {
log.Fatalf("Could not create Network namespace: %s", err)
}
fd, err := syscall.Open(netNsPath, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_EXCL, 0)
if err != nil {
log.Fatalf("Could not create Network namespace: %s", err)
}
syscall.Close(fd)
if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil {
log.Fatalf("Could not clone new Network namespace: %s", err)
}
if err := syscall.Mount(SelfNetNs, netNsPath, "none", syscall.MS_BIND, ""); err != nil {
log.Fatalf("Could not Mount Network namespace: %s", err)
}
if err := syscall.Unmount(netNsPath, syscall.MNT_DETACH); err != nil {
log.Fatalf("Could not Unmount new Network namespace: %s", err)
}
if err := syscall.Unlink(netNsPath); err != nil {
log.Fatalf("Could not Unlink new Network namespace: %s", err)
}
ifcs, _ := net.Interfaces()
for _, ifc := range ifcs {
fmt.Printf("%#v\n", ifc)
}
}
现在,当您在Trusty 14.04上运行此代码时,您将看到一些奇怪的事情发生。
当您连续多次运行二进制文件时,就会发生这种情况
有时它打印出所有主机的接口,有时它只是打印出一个环回接口,这意味着程序末尾的范围循环似乎在名称空间仍然附加时执行一次,有时在名称空间已经分离时执行一次
我完全搞不懂为什么会发生这种情况,但我认为这要么是我的代码,要么是我在程序执行或内核方面遗漏了一些东西
任何帮助都将不胜感激
谢谢
更新1:
因此,这种奇怪的行为似乎与golang如何跨操作系统线程调度GoRouting有关。因此,您需要确保能够很好地处理运行时。我的意思是,如果您将代码执行锁定到一个OS线程,您将获得一致的结果。可以通过添加以下运行时包语句来执行此操作:
runtime.LockOSThread()
然而,这仍然不能解决我的问题,但现在我认为这一切都归结于对名称空间的理解。我需要进一步调查
更新2:
为了让您了解为什么在运行一堆系统调用时应该使用上面的OS线程锁,并体验类似的奇怪的正确行为,请阅读本文。它描述了运行时和go调度程序。它是为go 1.1编写的,但它仍然提供了非常好的概述。我只知道tip是否仍然存在这种情况。从今天开始,在go v1.3rc2 tip上,它只打印lo,确实运行了20次,在arch linux上运行内核3.15。