Невозможно создать вложенное пространство имен сети

Кажется, что невозможно создать сетевое пространство имен из сетевого пространства имен. Это приводит к "Ошибка: ссылка на одноранговую сеть недействительна".

Это ошибка или есть какое-то ограничение, о котором я не знаю?

Ниже мой cmd след ошибки.

# ip netns add foo1
# ip netns exec foo1 ip netns add foo2
# ip netns
Error: Peer netns reference is invalid.
Error: Peer netns reference is invalid.
foo2
foo1
# ip netns exec foo2 /bin/bash
setting the network namespace "foo2" failed: Invalid argument

1 ответ

Решение

TL;DR: Как ни странно, на самом деле это не проблема пространства имен сети, а проблема монтирования пространства имен, и это следовало ожидать.

Вы должны создать все новые "пространства имен ip netns" (значение см. Далее), т.е. запустить все ip netns add ... команды из исходного (хоста) "пространства имен ip netns", а не изнутри "пространства имен ip netns", введенного с помощью ip netns exec ..., До тех пор, пока вы не создадите их, вы сможете свободно переключаться между ними, включая команды вложения от одной к другой, с ip netns exec ...,

Подробное объяснение с пошаговыми примерами следующего...


ip netns специализируется на сетевых пространствах имен, но для обработки всех функций также должен смешиваться с пространствами монтирования по двум причинам (по крайней мере, из тех, что мне известны):

  • крепление /etc/netns/FOO/SOMESERVICE в /etc/SOMESERVICE управлять альтернативными конфигурациями сервисов / демонов

    Функция, которая может быть удобна для простого запуска некоторых (связанных с сетью) демонов в другом пространстве имен сети, но помимо этого она все еще является частью "хоста". Вы можете проверить мой ответ в UL на вопрос об этом там: Управление пространством имен с помощью ip netns (iproute2). Его использование требует такой же обработки, как и следующая функция, поэтому я не буду больше об этом говорить.

  • перемонтажа /sys выставить сетевые устройства нового сетевого пространства имен в его иерархии

    Это обязательная функция. Пример выявления проблемы:

    С "начального хоста":

    # ip link add dev dummy9 type dummy
    # ip -br link show dummy9 
    dummy9           DOWN           f6:f6:48:9c:12:b9 <BROADCAST,NOARP> 
    # ls -l /sys/class/net/dummy9
    lrwxrwxrwx. 1 root root 0 Apr  4 22:09 /sys/class/net/dummy9 -> ../../devices/virtual/net/dummy9
    

    Использование инструмента более низкого уровня для перехода в другое (эфемерное) пространство имен сети:

    # unshare --net ip -br link show dummy9 
    Device "dummy9" does not exist.
    # unshare --net ls -l /sys/class/net/dummy9
    lrwxrwxrwx. 1 root root 0 Apr  4 22:13 /sys/class/net/dummy9 -> ../../devices/virtual/net/dummy9
    

    И это проблема: /sys по-прежнему предоставляет интерфейсы исходного хоста вместо интерфейса нового сетевого пространства имен. Вот где есть взаимодействие между сетевым пространством имен и с монтированием /sys: если /sysмонтируется из нового сетевого пространства имен, он переключится на отображение новых сетевых интерфейсов в выбранных иерархиях каталогов (например,/sys/class/netа также/sys/devices/virtual/net). Это делается только во время монтирования, а не динамически. Некоторые расширенные сетевые настройки легко доступны, просто читая или записывая их, поэтому их необходимо предоставить, и верно обратное: изолированные процессы, работающие в новой сетевой среде, не должны видеть или изменять интерфейсы исходного хоста.

Так ip netns exec FOO ...(но нетip netns add FOO) решает эту проблему, также отключая пространство имен монтирования и перемонтируя /sys/ внутри него, чтобы не нарушать пространство имен начальной сети. Но важно то, что это пространство имен монтирования само по себе эфемерно: при запуске по отдельности два ip netns exec FOO ...команды, они не попадают в одно и то же пространство имен монтирования. У каждого свой, с/sysперемонтирован там, указывая на то же пространство имен сети.

До сих пор проблем нет. Когда это произошло, я назову это "пространством имен ip netns", поскольку теперь задействованы два типа пространств имен. У нас так далеко:

term1:

# ip netns add FOO
# ls -l /proc/$$/ns/{mnt,net}
lrwxrwxrwx. 1 root root 0 Apr  4 22:28 /proc/1712/ns/mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 Apr  4 22:28 /proc/1712/ns/net -> net:[4026531992]
# ip netns exec FOO bash
# ls -l /proc/$$/ns/{mnt,net}
lrwxrwxrwx. 1 root root 0 Apr  4 22:33 /proc/1864/ns/mnt -> mnt:[4026532618]
lrwxrwxrwx. 1 root root 0 Apr  4 22:33 /proc/1864/ns/net -> net:[4026532520]

term2:

# ls -l /proc/$$/ns/{mnt,net}
lrwxrwxrwx. 1 root root 0 Apr  4 22:32 /proc/1761/ns/mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 Apr  4 22:32 /proc/1761/ns/net -> net:[4026531992]
# ip netns exec FOO bash
# ls -l /proc/$$/ns/{mnt,net}
lrwxrwxrwx. 1 root root 0 Apr  4 22:33 /proc/1866/ns/mnt -> mnt:[4026532821]
lrwxrwxrwx. 1 root root 0 Apr  4 22:33 /proc/1866/ns/net -> net:[4026532520]

Обратите внимание, что после изменения пространств имен ip netns, в то время как новое пространство имен сети одинаково для term1 иterm2, новые пространства имен монтирования отличаются друг от друга (и от исходного хоста).

Что происходит, когда вterm1 вы создаете новое пространство имен ip netns? Посмотрим:

term1:

# ip netns add BAR
# ip netns ls
BAR
FOO

term2:

# ip netns ls
Error: Peer netns reference is invalid.
Error: Peer netns reference is invalid.
BAR
FOO

Это связано с тем, что более новое пространство имен BAR, которое необходимо сохранить существующим без процесса, монтируется, как и другие (недавно созданный пустой файл)/var/run/netns/BAR (снова см. предыдущую ссылку для примеров). Хотя пространства имен монтирования различны, они имеют один и тот же корневой каталог: начальный корневой каталог хоста. Так что, конечно, этот недавно созданный пустой файл/var/run/netns/BARможно было увидеть везде (начальная буква,термины n1 монтирования, термины монтирования ter2), когда он был создан.

Увы, монтирование над ним, выполняемое в пространстве имен FOO для term1, можно увидеть только вterm1, но не вterm2 и нигде, потому что это другое пространство имен mount. Так что пока в term1 (это пространство имен FOO ip netns)/var/run/netns/BARпсевдофайл, принадлежащийnsfsпсевдо-файловая система:

term1:

# stat -f -c %T /var/run/netns/BAR
nsfs

Это пустой файл наtmpfs(из фактического/runсмонтировать) где-нибудь еще:

term2:

# stat -f -c %T /var/run/netns/BAR
tmpfs

Любой другой терминал:

$ stat -f -c %T /var/run/netns/BAR
tmpfs

Это все еще можно увидеть в term1, если не выйти из текущего "пространства имен ip netns". Если изterm1 все еще переключаются пространства имен ip netns, все будет хорошо, потому что новое неразделенное эфемерное пространство имен монтирования является копией предыдущего, включая все монтирования.

В случае выхода эта точка монтирования теряется (и это означает, что если процессы или дескрипторы файлов больше не используют ее, соответствующее пространство имен сети BAR исчезнет, ​​поскольку оно удерживалось только этой точкой монтирования). После этого любой ip netns ls Команда будет жаловаться, где угодно. Вы можете просто удалить устаревший и теперь бесполезный файл /run/netns/BARпочинить это.

После этого пошагового объяснения следует помнить, что вы не должны создавать новые пространства имен с ip netns add внутри пространства имен, введенного в данный момент сip netns exec, Вы должны создать их все из исходного (хоста) пространства имен, затем вы можете по желанию переключаться между ними из любого пространства имен ip netns.

Конечно, если/var/run/netns/(т.е. точка монтирования/run) различается (оставаясь нечетким) пространствами имен, то нет никакого взаимодействия, и каждыйip netnsвызов будет изолирован от других, не будет видеть и не взаимодействовать с другими. Где это обычно происходит? В полных контейнерах, где пространства имен монтирования и сети разделены и с самого начала указывают на разные ресурсы.


ОБНОВЛЕНИЕ: как просили в комментариях, я проверил, как "исправить" эту проблему, но не мог найти легкое решение.

Сначала есть предварительное условие: как сказано выше, как только внутри FOO создается новое пространство имен BAR "ip netns", а FOO остается, единственная ссылка на BAR исчезает, таким образом, делая BAR также исчезающим. Нужно что-то еще.

На самом деле есть три способа сохранить ссылку на пространство имен:

  • процесс: это основной метод, и в большинстве случаев именно так используется пространство имен
  • точка монтирования (это метод, используемыйip netns): позволяет сохранить пространство имен без какого-либо процесса, хорошо иметь пространство имен только с сетевыми настройками внутри (интерфейсы, мосты, правила tc, правила брандмауэра, ...)
  • дескриптор открытого файла: редко, используется при создании пространств имен, но редко сохраняется, за исключением приложений, работающих с несколькими пространствами имен одновременно и переключающих некоторые потоки с помощью файлового дескриптора для удобства обращения.

Мы можем использовать 1-й или 3-й метод. Вот несколько неудачных попыток, прежде чем найти что-то, что работает...

Как сказано ранее, не будет работать:

# ip netns add FOO
# ip netns exec FOO ip netns add BAR

Просто оставьте процесс, временно запущенный в первом пространстве имен "ip netns", для его эфемерной части пространства именмонтирования, чтобы сохранить необходимую ссылку на сетевое пространство имен нового пространства имен "ip netns" и использовать его позже снаружи (из исходного пространства имен).

Не сработает

# ip netns add FOO
# ip netns exec FOO sh -c 'ip netns add BAR; sleep 999 < /var/run/netns/BAR & echo $!'
28344
# strace -e trace=readlink,mount mount --bind /proc/6295/fd/0 /var/run/netns/BAR
readlink("/proc/6295/fd/0", "/run/netns/BAR", 4095) = 14
readlink("/var/run", "/run", 4095)      = 4
mount("/run/netns/BAR", "/run/netns/BAR", 0x55c88c9cccb0, MS_BIND, NULL) = 0
+++ exited with 0 +++
# stat -f -c %T /run/netns/BAR
tmpfs

Как видно сstracemountКоманда следовала по символической ссылке, когда она не должна иметь для этого варианта использования (примечание: монтирование все еще каким-то образом связано с процессом сна, который должен быть уничтожен, чтобы размонтировать его).

Это (входяsleep пространство имен монтирования, чтобы получить доступ к скрытому там сетевому пространству имен BAR, работает, но полагается на постоянное существованиеsleepили любой процесс для дальнейшего использования:

# ip netns add FOO
# ip netns exec FOO sh -c 'ip netns add BAR; ip -n BAR link add dummy8 type dummy; sleep 999 & echo $!'
12916
# nsenter --target=12916 --mount ip -n -brief BAR link show
lo               DOWN           00:00:00:00:00:00 <LOOPBACK> 
dummy8           DOWN           8e:ce:b3:d1:9c:bb <BROADCAST,NOARP> 

странно это (используя ярлык пространства имен монтирования/proc/pid/root/) не работает (я не знаю почему):

# stat -f -c %T /proc/12916/root/var/run/netns/BAR 
tmpfs

Наконец то, что будет работать:

# ip netns add FOO
# ip netns exec FOO sh -c 'ip netns add BAR; ip -n BAR link add dummy8 type dummy; ip netns exec BAR sh -c '\''sleep 999 & echo $!'\'
14124
# mount --bind /proc/14124/ns/net /var/run/netns/BAR
# ip -n BAR -brief link show
lo               DOWN           00:00:00:00:00:00 <LOOPBACK> 
dummy8           DOWN           3a:48:65:20:68:c1 <BROADCAST,NOARP> 

Так что-то подобное может быть использовано в конце. Могут возникнуть условия гонки, если вы попытаетесь удалить их сразу после завершения команды сна.

# ip netns add FOO
# mount --bind /proc/$(ip netns exec FOO sh -c 'ip netns add BAR; ip netns exec BAR bash -c '\''sleep 5 </dev/null >/dev/null 2>&1 & echo $!; disown'\')/ns/net /var/run/netns/BAR

Как можно использовать такую ​​конструкцию? Понятия не имею, потому что исходная проблема до появления вложенной проблемы "ip netns" не была дана. Возможно, более простые решения доступны, даже не пытаясь создать "вложенное пространство имен сети".

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