Calico Kubernetes the hard way v2 How packet goes from pod
Calico: как пакет выходит из POD
Это заметка про Calico, где рассматривается небольшая часть пути пакета - как пакет покидает POD.
Она появилась по-тому что сеть сделана в Calico не совсем классическим способом, и используются механизмы которые редко можно встретить за пределами сетей провайдеров.
"Странности" внутри PODa
Внутри POD
таблица маршрутизации выглядит достаточно необычно:
route -n
Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 169.254.1.1 0.0.0.0 UG 0 0 0 eth0 169.254.1.1 0.0.0.0 255.255.255.255 UH 0 0 0 eth0
При этом на первый взгляд выглядит так как-будто работать такая схема не должна
Адрес 169.254.1.1 это вообще Link-Local address
На интерфейсе установлен адрес с маской /32, в качестве шлюза указан адрес доступный непосредственно через интерфейс
ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450 inet 10.244.235.132 netmask 255.255.255.255 broadcast 0.0.0.0 inet6 fe80::68a6:d0ff:fe94:1d10 prefixlen 64 scopeid 0x20<link> ether 6a:a6:d0:94:1d:10 txqueuelen 0 (Ethernet) RX packets 5 bytes 446 (446.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 17 bytes 1286 (1.2 KB) TX errors 0 dropped 1 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Сам интерфейс внутри POD
представляет из себя обычный для контейнеров veth
, второй конец которой находится за пределами сетевого пространства имен POD
,
для того что бы найти второй конец виртуального линка можно определить peer_ifindex
ethtool -S eth0 NIC statistics: peer_ifindex: 254 rx_queue_0_xdp_packets: 0 rx_queue_0_xdp_bytes: 0 rx_queue_0_xdp_drops: 0
В примере выше peer_ifindex: 254
это и есть индекс искомого интерфейса (на хосте, за пределами POD), который можно увидеть командой ip link show
ip -d link show
254 это и есть найденный peer_ifindex
... 254: calieede18e00ae@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP mode DEFAULT group default link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 13 promiscuity 0 minmtu 68 maxmtu 65535 veth addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 RX: bytes packets errors dropped overrun mcast 237561215 1243131 0 0 0 0 TX: bytes packets errors dropped carrier collsns 236237144 1273779 0 0 0 0
Как это работает (отправка пакета из POD
)
Для того что бы POD
мог отправить пакет, он проделывает следующие шаги:
- просматривает таблицу маршрутизации
- так как в таблице всего одна запись, шлюз, то все пакеты будут отправляться на шлюз
- для того что бы отправить пакет на шлюз необходимо знать МАК-адрес шлюза, соответственно необходима запись в arp-таблице
- для ее создания будет создан arp-запрос
Но, так как (со стороны хоста, за пределами контейнера) на ответной части интерфейса eth0, интерфейсе calieede18e00ae
нет никакого ip адреса, возникает вопрос.
Откуда берется arp-ответ?
Linux proxy_arp
Короткий ответ на вопрос - это "proxy arp
".
Для того что бы в первом приближении понять что механизм proxy_arp
включен, можно проверить sysctl
:
sysctl -a | grep calieede18e00ae | grep -v ipv6
Вывод сокращен:
... net.ipv4.conf.calieede18e00ae.proxy_arp = 1 net.ipv4.conf.calieede18e00ae.proxy_arp_pvlan = 0 net.ipv4.neigh.calieede18e00ae.proxy_delay = 0 ...
Из вывода видно (net.ipv4.conf.calieede18e00ae.proxy_arp = 1
), что для интерфейса механизм proxy_arp
включен (1)
Далее рассмотрим его работу более подробно.