Change linux namespace in go

huangapple go评论79阅读模式
英文:

Change linux namespace in go

问题

我想在Go语言中更改命名空间。当我在C中编译和运行代码时,一切都正常,但在Go中,netns系统调用返回了错误号22。有任何想法为什么会发生这种情况吗?

以下是要翻译的内容:

我想在Go语言中更改命名空间。当我在C中编译和运行代码时,一切都正常,但在Go中,netns系统调用返回了错误号22。有任何想法为什么会发生这种情况吗?

go)

$ go build main.go ; ./main
setns mnt: Invalid argument
panic: -1

goroutine 1 [running]:
runtime.panic(0x423b80, 0xffffffffffffffff)
	/usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
main.main()
	main.go:81 +0x86
$

c)

$ grep ^// main.go | sed 's/\/\///' | sed 's/__main/main/' > main.c; gcc main.c -o main; ./main
$

以下是代码:

package main

//
// #define _GNU_SOURCE
// #include <fcntl.h>
// #include <sched.h>
// #include <sys/syscall.h>
// #include <sys/param.h>
// #include <sys/mount.h>
// #include <stdio.h>
// #include <unistd.h>
//
// #define NETNS_RUN_DIR "/run/netns"
// #define MNTNS_RUN_DIR "/run/mntns"
//
// #ifndef HAVE_SETNS
//
// int
// setns(int fd, int nstype) {
// #ifdef __NR_setns
//   return syscall(__NR_setns, fd, nstype);
// #else
//   errno = ENOSYS;
//   return -1;
// #endif
// }
//
// #endif /* HAVE_SETNS */
//
//
// int
// ChangeNamespace(char *name)
// {
//   char net_path[MAXPATHLEN];
//   char mnt_path[MAXPATHLEN];
//   int fd;
//
//   snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
//   snprintf(mnt_path, sizeof(mnt_path), "%s/%s", MNTNS_RUN_DIR, name);
//
//   fd = open(net_path, O_RDONLY);
//   if (fd < 0) {
//     perror("open net");
//     return -1;
//   }
//
//   if (setns(fd, 0) < 0) {
//     perror("setns net");
//     return -1;
//   }
//
//   fd = open(mnt_path, O_RDONLY);
//   if (fd < 0) {
//     perror("open mnt");
//     return -1;
//   }
//
//   if (setns(fd, 0) < 0) {
//     perror("setns mnt");
//     return -1;
//   }
//
//   return 0;
// }
//
// int
// __main(int argc, char *argv[]) {
//     ChangeNamespace("ns");
//     return 0;
// }
//
import "C"
import "unsafe"
func main() {
	name := C.CString("ns")
	defer C.free(unsafe.Pointer(name))
	i := int(C.ChangeNamespace(name))
	if i < 0 {
		panic(i)
	}
}
英文:

I want to change namespace in go. When I'm compiling and running code in C it works fine, but in go I got errno 22 on netns syscall. Any Idea why this could occur?

go)

$ go build main.go ; ./main
setns mnt: Invalid argument
panic: -1

goroutine 1 [running]:
runtime.panic(0x423b80, 0xffffffffffffffff)
	/usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
main.main()
	main.go:81 +0x86
$

c)

$ grep ^// main.go | sed &#39;s/\/\///&#39; | sed &#39;s/__main/main/&#39; &gt; main.c; gcc main.c -o main; ./main
$

The code below:

package main

//
// #define _GNU_SOURCE
// #include &lt;fcntl.h&gt;
// #include &lt;sched.h&gt;
// #include &lt;sys/syscall.h&gt;
// #include &lt;sys/param.h&gt;
// #include &lt;sys/mount.h&gt;
// #include &lt;stdio.h&gt;
// #include &lt;unistd.h&gt;
//
// #define NETNS_RUN_DIR &quot;/run/netns&quot;
// #define MNTNS_RUN_DIR &quot;/run/mntns&quot;
//
// #ifndef HAVE_SETNS
//
// int
// setns(int fd, int nstype) {
// #ifdef __NR_setns
//   return syscall(__NR_setns, fd, nstype);
// #else
//   errno = ENOSYS;
//   return -1;
// #endif
// }
//
// #endif /* HAVE_SETNS */
//
//
// int
// ChangeNamespace(char *name)
// {
//   char net_path[MAXPATHLEN];
//   char mnt_path[MAXPATHLEN];
//   int fd;
//
//   snprintf(net_path, sizeof(net_path), &quot;%s/%s&quot;, NETNS_RUN_DIR, name);
//   snprintf(mnt_path, sizeof(mnt_path), &quot;%s/%s&quot;, MNTNS_RUN_DIR, name);
//
//   fd = open(net_path, O_RDONLY);
//   if (fd &lt; 0) {
//     perror(&quot;open net&quot;);
//     return -1;
//   }
//
//   if (setns(fd, 0) &lt; 0) {
//     perror(&quot;setns net&quot;);
//     return -1;
//   }
//
//   fd = open(mnt_path, O_RDONLY);
//   if (fd &lt; 0) {
//     perror(&quot;open mnt&quot;);
//     return -1;
//   }
//
//   if (setns(fd, 0) &lt; 0) {
//     perror(&quot;setns mnt&quot;);
//     return -1;
//   }
//
//   return 0;
// }
//
// int
// __main(int argc, char *argv[]) {
//     ChangeNamespace(&quot;ns&quot;);
//     return 0;
// }
//
import &quot;C&quot;
import &quot;unsafe&quot;
func main() {
	name := C.CString(&quot;ns&quot;)
	defer C.free(unsafe.Pointer(name))
	i := int(C.ChangeNamespace(name))
	if i &lt; 0 {
		panic(i)
	}
}

答案1

得分: 5

你可以使用类似这样的代码来完全跳过cgo,我现在无法测试它:

const (
    netNS = "/run/netns/"
    mntNS = "/run/mntns/"
)

func ChangeNamespace(name string) error {
    fd, err := syscall.Open(netNS+name, syscall.O_RDONLY, 0666)
    if err != nil {
        return err
    }
    defer syscall.Close(fd)
    if _, _, err := syscall.RawSyscall(syscall.SYS_SETNS, uintptr(fd), 0, 0); err != nil {
        return err
    }

    fd1, err := syscall.Open(mntNS+name, syscall.O_RDONLY, 0666)
    if err != nil {
        return err
    }
    defer syscall.Close(fd1)
    if _, _, err := syscall.RawSyscall(syscall.SYS_SETNS, uintptr(fd1), 0, 0); err != nil {
        return err
    }
    return nil
}

希望对你有帮助!

英文:

You could use something like this skipping the cgo all together, I can't test it right now:

const (
	netNS = &quot;/run/netns/&quot;
	mntNS = &quot;/run/mntns/&quot;
)
func ChangeNamespace(name string) error {
	fd, err := syscall.Open(netNS+name, syscall.O_RDONLY, 0666)
	if err != nil {
		return err
	}
	defer syscall.Close(fd)
	if _, _, err := syscall.RawSyscall(syscall.SYS_SETNS, uintptr(fd), 0, 0); err != nil {
		return err
	}

	fd1, err := syscall.Open(mntNS+name, syscall.O_RDONLY, 0666)
	if err != nil {
		return err
	}
	defer syscall.Close(fd1)
	if _, _, err := syscall.RawSyscall(syscall.SYS_SETNS, uintptr(fd1), 0, 0); err != nil {
		return err
	}
    return nil
}

huangapple
  • 本文由 发表于 2014年9月4日 23:07:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/25668980.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定