Пространство имен Linux Network неожиданное поведение

Так что я недавно поиграл с сетевыми пространствами имен. Я собрал простой код, собрал его и заметил нечто очень странное.

Код выглядит следующим образом:

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 распределяет программы между потоками ОС. Поэтому вам нужно убедиться, что вы хорошо справляетесь со временем выполнения. Под этим я подразумеваю, что если вы заблокируете выполнение кода в одном потоке ОС, вы получите согласованные результаты. Вы можете сделать это, добавив следующий оператор пакета времени выполнения:

runtime.LockOSThread()

Однако это все еще не решает мою проблему, но теперь я думаю, что все сводится к пониманию пространств имен. Мне нужно больше посмотреть на это.

Обновление 2: чтобы дать вам немного больше смысла в том, почему вы должны использовать вышеупомянутую блокировку потока ОС при запуске группы системных вызовов и испытывать подобную "странность" правильного поведения, прочитайте эту статью в блоге. Описывает время выполнения и идут планировщики. Он был написан для Go 1.1, но он все еще дает очень хороший обзор.

0 ответов

Другие вопросы по тегам