Calico Kubernetes the hard way v2 How tunl0 works
Как работает IP-in-IP
туннель в Calico
Это один из вариантов конфигурации Calico.
Эта статья появилась так-как настройка туннеля не очень-то очевидна.
Схема сети
- Показаны только 2 ноды, для простоты.
- 192.168.122.0/24 - физическая сеть
+----------------------------------------+ +----------------------------------------+ | Host: worker1 | | Host: worker2 | | +---------------------+ | | +---------------------+ | | | POD1 | | | | POD2 | | | | | | | | | | | | 10.244.235.132/32 | | | | 10.244.189.171/32 | | | +---eth0--------------+ | | +---eth0--------------+ | | | | | | | | | | | | | | caliXXXX | | caliYYYY | | На этом интерфейсе НЕТ ip адреса | | На этом интерфейсе НЕТ ip адреса | | | | | | [ tunl0 ] 10.244.235.136/32 | | [ tunl0 ] 10.244.189.71/32 | | | | | +--[ eth0 ]-----------------------------+ +--[ eth0 ]-----------------------------+ 192.168.122.88/24 192.168.122.125/24 | | +---------------------------------------------------------------+
Настройки интерфейса tunl0
Calico
Если не особо вдумываться, то в настройке интерфейса (одинаковом на всех нодах, с одинаковыми настройками) нет ничего необычного
ip -d link show dev tunl0
2: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 promiscuity 0 ipip remote any local any ttl inherit nopmtudisc addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
Однако, если смотреть внимательно то вызывает вопрос вот эта часть конфигурации
link/ipip 0.0.0.0 brd 0.0.0.0 promiscuity 0 ipip remote any local any <PRE> Поясню: обычно <code>ipip</code> туннели представляют собой соединения точка-точка, при этом в настройках туннеля указываются адреса концов туннеля.<br> Например классический туннель создается командой <PRE> ip tunnel add mytun mode ipip remote 251.4.92.217 local 240.101.83.2
IP адреса тут взяты "из головы" и приведены только для примера.
Соответственно, в настройках туннеля можно видеть "оба конца" туннеля.
3: mytun@NONE: <POINTOPOINT,NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 240.101.83.2 peer 251.4.92.217 promiscuity 0 ipip remote 251.4.92.217 local 240.101.83.2 ttl inherit pmtudisc numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
Подчеркну, что это именно "транспортные" адреса, между которыми должна быть L3 связность, и это не те адреса которые настроены на интерфейсе mytun
Совершенно не понятно как работает туннель не имеющих определенных "концов" - что с чем связывает туннель с ipip remote any local any
Этот вопрос и разбирается в этой статье.
tunl0
и его особенности
Как показало длительное чтение документации и еще более длительный поиск в интернетах, у модуля ядра ipip
есть хоть и документированная, но мало кому известная особенность, а именно.
Note: When the ipip module is loaded, or an IPIP device is created for the first time, the Linux kernel will create a tunl0 default device in each namespace, with attributes local=any and remote=any. When receiving IPIP protocol packets, the kernel will forward them to tunl0 as a fallback device if it can't find another device whose local/remote attributes match their source or destination address more closely.
Перевод:
Обратите внимание на то, что когда загружен модуль ipip, или когда впервые создано IPIP-устройство, ядро Linux создаст в каждом пространстве имён устройство по умолчанию tunl0 с атрибутами local=any и remote=any. Получая IPIP-пакеты, ядро, в определённых случаях, будет перенаправлять их на tunl0 как на устройство, используемое по умолчанию. Это происходит тогда, когда ядро не может найти другого устройства, атрибуты local/remote которого более точно соответствуют адресам источника и приёмника пакетов.
Другими словами, интерфейс tunl0
(и да - он присутствует во всех network namespaces, а значит его можно видеть во всех POD
будет осуществлять деинкапсуляцию
для любого пакета, который не попал до того в другой интерфейс типа ipip tunnel
. Эта схема работает, так как в ipip tunnel
нет ничего что бы напоминало идентификатор интерфейса,
вроде Vlan ID
или VxLAN VNI
, а так же нет штатного шифрования.
Итого, любой пакет который является ipip
пакетом и не был помещен в туннельный интерфейс по совпадению local/remote, в конце концов не будет отброшен а будет помешен в интерфейс tunl0
(на мой взгляд это не совсем логичное поведение, но тем не менее именно оно позволяет организовать работу Calico)
Настройка tunl0
(в ручном режиме)
Для того что бы понять что делает Calico
нужно воспроизвести все шаги по созданию и настройки интерфейса tunl0
- Загрузить модуль
ipip
(если не был загружен до того), на обоих нодах
modprobe ipip
- Убедиться в том что модуль загрузился без ошибок, на обоих нодах
lsmod | grep ipip
ipip 16384 0 tunnel4 16384 1 ipip ip_tunnel 24576 1 ipip
dmesg -T | grep ipip [Чт дек 22 17:16:51 2022] ipip: IPv4 and MPLS over IPv4 tunneling driver
- Добавить IP адреса на тунельном интерфейсе (Важно - это адреса именно на туннеле, а не адреса транспортные адреса, транспортные остаются все так же
any/any
ip addr add 10.244.189.71/32 dev tunl0 ip link set up dev tunl0
ip addr add 10.244.235.136/32 dev tunl0 ip link set up dev tunl0
Далее происходит некая "магическая" последовательность действий - маршруты onlink
Особенности маршрутизации и onlink
Для лучшего понимания рассмотрим пример таблицы маршрутизации одной из нод (оставлены только значимые части):
10.244.182.0 192.168.122.114 255.255.255.192 UG 0 0 0 tunl0 192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 enp1s0
Эти две записи вместе выглядят очень странно
- C одной стороны для достижения сети
10.244.182.0/26
предполагается использование шлюза192.168.122.114
и интерфейсаtunl0
(на это указывает первая строка в таблице) - С другой стороны, для адреса шлюза
192.168.122.114
должен использоваться интерфейсenp1s0
, а не интерфейсtunl0
(на это указывает вторая строка в таблице)
Тут стоит отметить, что утилита route
устаревшая и показывает не все параметры таблицы, если посмотреть с помощью ip
то можно видеть атрибуты маршрутов.
ip route
10.244.182.0/26 via 192.168.122.114 dev tunl0 proto bird onlink
Обратить внимание на onlink
,
proto bird
не является значащим в контексте туннелирования, можно игнорировать
Вот цитата из руководства iproute2
https://man7.org/linux/man-pages/man8/ip-route.8.html
onlink pretend that the nexthop is directly attached to this link, even if it does not match any interface prefix.
Это означает что для маршрутов с таким флагом onlink не обязательно иметь адрес назначенный на интерфейсе
который находился бы в одной сети с шлюзом, через которые отправлять пакеты.
Другими словами, команда создаст особый тип маршрута.
Пакет, отправленный через этот маршрут пройдя через интерфейс tunl0
, будет обернут в дополнительные заголовки IP и отправлен на шлюз 192.168.122.114
ip ro add 10.244.182.0/24 via 192.168.122.114 dev tunl0 onlink
Важная заметка про onlink
По-сути, если крепко вдуматься, то никакой особой сетевой магии тут не происходит.
текст описания просто по-дебильному написан.
Попробую более понятно пояснить своими словами.
Ключевое слово тут - link
ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: tunl0@NONE: <NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/ipip 0.0.0.0 brd 0.0.0.0 3: mytun@NONE: <POINTOPOINT,NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ipip 240.101.83.2 peer 251.4.92.217 4: veth11@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 42:56:a7:07:b9:34 brd ff:ff:ff:ff:ff:ff link-netnsid 1 5: veth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 66:72:3f:f6:1d:3f brd ff:ff:ff:ff:ff:ff link-netnsid 1 6: veth11.11@veth11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 42:56:a7:07:b9:34 brd ff:ff:ff:ff:ff:ff
В случае интерфейсов типа ipip
никакого другого link
кроме IP нет, что можно видеть в выводе команды: link/ipip 0.0.0.0 brd 0.0.0.0
Для сравнения, что бы отправить пакет через ether
нужны link-layer
адреса - МАК.
В случае же такого специфичного интерфейса как tunl0
своеобразной заменой МАК-адресам выступают IP адреса, и пакет отправляется соответственно адрес via
(например via 192.168.122.114
)из таблицы маршрутизации, который выступает в качестве link-layer
адреса получателя, своеобразная замена МАК-адреса
ether-like
интерфейсов.
Получение пакета на другой ноде
Это самая простая и понятная часть - тут происходит "магия" tunl0
Так как на ноде, куда отправлен пакет, нет других туннельных интерфейсов то пакет с инкапсуляцией ipip
будет обработан, дополнительные заголовки IP будут сняты, и далее пакет можно будет увидеть на интерфейсе tunl0
После этого пакет будет отправлен далее согласно таблице маршрутизации.
Ссылки
- https://habr.com/ru/post/48276/
- https://lartc.vger.kernel.narkive.com/XgcjFTGM/aw-onlink-option-for-ip-route
- https://habr.com/ru/company/ruvds/blog/457386/
- https://habr.com/ru/post/48276/
- https://man7.org/linux/man-pages/man8/ip-link.8.html
- https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels#ip6gre_and_ip6gretap
- https://weril.me/ifconfig/
- https://www.oreilly.com/library/view/wireless-hacks/0596005598/ch04s13.html
- https://medium.com/@samueldarwin/full-mesh-ipip-tunnels-d16888913e40
- http://www.asznl.com/post/85 - имитация сети Calico (надо переводить переводчиком)