Назад | Перейти на главную страницу

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

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

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

Ниже мой 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

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, в то время как новое сетевое пространство имен остается таким же для термин1 и термин2, новые пространства имен монтирования отличаются друг от друга (и от исходного хоста).

Что теперь происходит, когда в термин1 вы создаете новое пространство имен 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, которое должно существовать без процесса, как и другие, установленный on (вновь созданный пустой файл) /var/run/netns/BAR (снова см. предыдущая ссылка Например). Хотя пространства имен монтирования различны, они имеют один и тот же корневой каталог: корень исходного хоста. Итак, конечно, этот вновь созданный пустой файл /var/run/netns/BAR можно было увидеть везде (начальный, термин1s mount ns, термин2's mount ns), когда он был создан.

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

term1:

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

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

term2:

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

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

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

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

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

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

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


ОБНОВИТЬ: как просили в комментариях, я проверил, как «исправить» эту проблему, но не нашел простого решения.

Во-первых, есть предварительное условие: как сказано выше, после того, как новое пространство имен "ip netns" BAR будет создано внутри FOO, а 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

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

Это (входящий 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> 

как ни странно это (используя ярлык пространства имен mount /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" не была указана. Возможно, доступны более простые решения, даже без попыток создать «вложенное сетевое пространство имен».