OpenStack Neutron Floating Ip
TL;DR
Краткий список команд
Как трафик попадает из внешнего мира на VM в OpenStack
Этот документ описывает как трафик из внешнего мира доходит до виртуальных машин в OpenStack (один из возможных вариантов реализации).
Описание окружения
Окружение с установленным OpenStack состоит из 3 Control Nodes и они же совмещают роль Network Node, и одной Compute Node (минимально-возможное количество)
Для получения трафика из-вне используется интерфейс с именем floating
(имя может быть выбрано произвольно)
Исследование пути трафика
В окружении (для простоты) запущен один единственный инстанс, у которого Floating IP 10.72.10.124
os server list
+--------------------------------------+--------------------------+--------+----------------------------------------+------------+--------------------+ | ID | Name | Status | Networks | Image | Flavor | +--------------------------------------+--------------------------+--------+----------------------------------------+------------+--------------------+ | 795dc7f8-15b4-4b5d-9f8d-c40f178467f7 | test-cirros-vm-on-nvme-1 | ACTIVE | lb-mgmt-net=10.255.4.184, 10.72.10.124 | Cirros-5.1 | m1.nano.vm-on-nvme | +--------------------------------------+--------------------------+--------+----------------------------------------+------------+--------------------+
Сеть для floating Ips (10.72.10.0/24) настроена на маршрутизаторе в Vlan 729, и этот Vlan приходит в интерфейс с именем floating
на каждой из Controller/Network nodes
Шлюзом для Floating сети выступает внешний по отношению к OpenStack маршрутизатор.
С тестового ноутбука до виртуальной машины маршрут выглядит так:
Keys: Help Display mode Restart statistics Order of fields quit Packets Pings Host Loss% Snt Last Avg Best Wrst StDev 1. 192.168.33.1 0.0% 6 2.0 1.7 1.5 2.0 0.2 2. 10.72.10.124 0.0% 5 2.2 2.1 1.7 2.4 0.3
Определени через какую Network (Control/Network) ноду пойдет трафик
Из маршрута можно сделать следующие выводы:
- так как 192.168.33.1 -это адрес шлюза по-умолчанию для ноутбука с которого делается трассировка маршрута, а адрес VM
10.72.10.124
уже следующий в трассировке, то можно предположить что этот маршрутизатор и выступает шлюзом для floating сеть 10.72.10.0/24 - Если это утверждение верно, то изучив таблицу arp-записей на маршрутизаторе, возможно узнать мак-адрес VM (точнее, мак-адрес с которого уходит трафик от этой VM, этот адрес будет отличаться от того который можно посмотреть командой
ip link show
на самой VM.
В реальной жизни в окружении клиента доступа на роутеры и коммутаторы может не быть и тогда единственный способ понять через какую Compute/Network ноду идет трафик - это использовать tcpdump
Просмотр таблицы arp
на маршрутизаторе
В качестве маршрутизатора в этом (тестовом!) окружении выступает устройство Mikrotik RB4011iGS+5HacQ2HnD (RouterOS 7.4)
(это не типичная инсталляция, для других случаев маршрутизатор скорее всего окажется другого производителя)
Просматриваем таблицу arp-записей (с поиском по ip=10.72.10.124)
[admin@RB4011iGS+5HacQ2HnD] > /ip/arp/print where address=10.72.10.124
Flags: D, P - PUBLISHED; C - COMPLETE Columns: ADDRESS, MAC-ADDRESS, INTERFACE # ADDRESS MAC-ADDRESS INTERFACE 0 DC 10.72.10.124 FA:16:3E:40:32:D5 bridge-mosk-vlan-729-ch-os-fl
Из этого вывода можно видеть что
- мак-адрес хоста <cod>10.72.10.124 известен роутеру:
FA:16:3E:40:32:D5
- этот адрес изучен на физическом интерфейсе
bridge-mosk-vlan-729-ch-os-fl
- этот интерфейс (
bridge-mosk-vlan-729-ch-os-fl
) и является шлюзом для floating сети, на нем назначен первый адрес 10.72.10.1/24 из этого ( 10.72.10.0/24) диапазона
/ip/address/print where interface=bridge-mosk-vlan-729-ch-os-fl
Columns: ADDRESS, NETWORK, INTERFACE # ADDRESS NETWORK INTERFACE 0 10.72.10.1/24 10.72.10.0 bridge-mosk-vlan-729-ch-os-fl
- Проверить какие еще адреса имеют мак такой же как и у адреса с которого отвечает VM:
[admin@RB4011iGS+5HacQ2HnD] > /ip/arp/print where mac-address=FA:16:3E:40:32:D5
Flags: D, P - PUBLISHED; C - COMPLETE Columns: ADDRESS, MAC-ADDRESS, INTERFACE # ADDRESS MAC-ADDRESS INTERFACE 0 DC 10.72.10.124 FA:16:3E:40:32:D5 bridge-mosk-vlan-729-ch-os-fl 1 DC 10.72.10.27 FA:16:3E:40:32:D5 bridge-mosk-vlan-729-ch-os-fl
Тут видно что есть еще один IP с таким же маком - можно предположить что это или еще одна виртуальная машина, которая выходит через тот же роутер, или собственно адрес самого роутера.
В нашем простейшем случае, очевидно что это не может быть адресом виртуальной машины, так как в клауде запущена всего одна виртуальная машина с адресом 10.72.10.124
Просмотреть роутеры можно командой openstack router list
+--------------------------------------+------+--------+-------+----------------------------------+-------------+-------+ | ID | Name | Status | State | Project | Distributed | HA | +--------------------------------------+------+--------+-------+----------------------------------+-------------+-------+ | 54550846-33f2-4954-8649-3233a49cedb4 | r2 | ACTIVE | UP | 93900840d7804fd2adfe9bfd452263c7 | False | False | | 6cf2a3cc-5242-42b5-8c57-3ee78b0d0983 | r1 | ACTIVE | UP | 10510c89d63d490b967f90511cdc902d | True | False | +--------------------------------------+------+--------+-------+----------------------------------+-------------+-------+
А подробно информацию о роутере:
openstack router show 54550846-33f2-4954-8649-3233a49cedb4
(вывод команды немного отформатирован для лучшей читаемости)
+-------------------------+------------------------------------------------------------------- | Field | Value +-------------------------+------------------------------------------------------------------- | admin_state_up | UP | availability_zone_hints | | availability_zones | nova | created_at | 2023-02-27T14:15:39Z | description | router_for_nat | distributed | False | external_gateway_info | {"network_id": "5b1a5b04-b5ed-4ced-a097-585f40b0a5fd", | "external_fixed_ips": [ | {"subnet_id": "32d92f06-a3c7-42f1-9dbc-0eee02aa47c1", "ip_address": "10.72.10.27"} | ], | "enable_snat": false} | flavor_id | None | ha | False | id | 54550846-33f2-4954-8649-3233a49cedb4 | interfaces_info | [ | {"port_id": "e02600f1-cd39-4f1d-b1bc-c619602087b0", | "ip_address": "10.255.0.1", | "subnet_id": "4383ea14-91b6-49f9-98fa-8d6993012da2"} | ] | name | r2 | project_id | 93900840d7804fd2adfe9bfd452263c7 | revision_number | 10 | routes | | status | ACTIVE | tags | | updated_at | 2023-02-28T13:10:28Z +-------------------------+---------------------------------------
Сам по себе роутер в OpenStack это НЕ виртуальная машина, а network namespace
(сущность ядра Linux на Network Node)
Просмотр таблицы коммутации на top-of-rack switch
Зная мак-адрес целевой виртуальной машины, можно определить с какого порта коммутатора "виден" мак (правильно говорить: на каком порту коммутатора был изучен этот мак, но тут и далее я пользуюсь чаще сленговыми терминами)
В этой инсталляции в качестве коммутатора для всех нод используется Cisco Сatalyst WS-C3750E-48PD
Просмотреть с какого порта был изучен мак-адрес можно следующей командой:
c3750e-lab#show mac address-table address fa16.3e40.32d5
(Обратите внимания, что формат показа мак-адресов у различных вендоров может отличаться, и следует это учитывать.)
Mac Address Table ------------------------------------------- Vlan Mac Address Type Ports ---- ----------- -------- ----- 729 fa16.3e40.32d5 DYNAMIC Gi1/0/7
Из вывода команды можно видеть что
- Мак-адрес изучен с 7-го порта (Gi1/0/7)
- Мак-адерс находится в 729 Vlan (это было понятно еще на роутере по имени интерфейса
bridge-mosk-vlan-729-ch-os-fl
, так как в его имени содержится информация vlan: 729 os: OpenStack, fl: floatiung network, но в общем случае такой информации не будет, и этот сетап - исключение, так как при настройке заведомо предполагалось упрощение дебага.
Зная номер порта, можно обратится к документации по клауду, и определить какой сервер подключен в какой порт.
(если документация недоступна то можно попробовать определить по тому какие еще мак-адреса присутствуют на порту, в других Vlan)
В этой инсталляции (где документация есть) определяем что в порт подключен к Control/Network Node c адресом 10.72.5.11
Прохождение тарфика внутри Compute Node
В этом сетапе - это нода 10.72.5.11
kaas-node-b4d3a72a-abe6-4dba-9547-30915084c409
Vlan 729 заходит в интерфейс с именем floating
- это имя дано специально, в общем случае имя может отличаться
- на этом интерфейсе уже нет никаких тегов - они снимаются раньше, другими словами tcpdump -i floating -n -ee не покажет тегированного трафика,
для данного случая не принципиально как именно снимается тег
- на этом интерфейсе нет ip адреса
<code>ip addr show dev floating</code> 7: floating: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master ovs-system state UP group default qlen 1000 link/ether 52:54:15:ac:ac:16 brd ff:ff:ff:ff:ff:ff inet6 fe80::5054:15ff:feac:ac16/64 scope link valid_lft forever preferred_lft forever
Изначально на этом интерфейсе присутствовал ip адрес - это в целом не мешало работе виртуальных машин, однако они не были доступны с этой ноды (но были доступны из сети).
Это была ошибка конфигурации, в целом назначать адреса на порты бриджа не правильно.
- Детальная информация по интерфейсу:
ip -d link show dev floating
7: floating: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master ovs-system state UP mode DEFAULT group default qlen 1000 link/ether 52:54:15:ac:ac:16 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65535 openvswitch_slave addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
Тут важно что этот интерфейс включен как порт OpenVSwitch (что видно из строки openvswitch_slave ) и, соответвенно трафик попавший в этот интерфейс попадает в openvswitch
Прохождение трафика внутри OpenVSwitch
OpenVSwitch представляет собой программную реализацию OpenFlow коммутатора, (точнее в пределах одной Linux ноды можно создать несколько независимо работающих OpenFlow коммутаторов)
В этой инсталляции процессы openvswitch работают внутри docker-контейнера, по этой причине все команды для работы с openvswitch нужно запускать оттуда:
docker exec -ti 1d8e520565ba ovs-vsctl show
однако для простоты в дальнейшем я буду опускать docker exec ...
Выяснить в какой виртуальный свитч попадает трафик
Выша было выяснено, что трафик уходит в недра OpenVSwitch, однако теперь предстоит выяснить в какой именно виртуальный коммутатора попадает трафик
Для этого просмотрим все виртуальные коммутаторы:
ovs-vsctl show
Часть вывода команды скрыта, полный вывод см ниже, тут оставлена только значимая часть
Bridge br-ch-os-fl Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure datapath_type: system Port br-ch-os-fl Interface br-ch-os-fl type: internal Port phy-br-ch-os-fl Interface phy-br-ch-os-fl type: patch options: {peer=int-br-ch-os-fl} Port floating Interface floating
Тут ключевые моменты такие
- Виртуальный коммутатор
br-ch-os-fl
, одним из портов (Port floating
) которого и является интерфейсInterface floating
является тем коммутатором куда попадает трафик - Этот коммутатор подключен к контроллеру,
is_connected: true
- Кроме порта через который в него попадает внешний трафик (
floating
), у него есть еще 2 порта:Port phy-br-ch-os-fl
Это порт имеет типtype: internal
что означает что он виден в системе и на него можно назначить адрес (прочитать подробнее можно тут: https://arthurchiao.art/blog/ovs-deep-dive-6-internal-port/
Port br-ch-os-fl
Этот порт имеет тип type: patch и предназначен для соединения нескольких виртуальных коммутаторов между собой, второй конец этого виртуального патч-корда имеет имяint-br-ch-os-fl
. В целом, это напоминает работу интерфейсаveth
Прохождение трафика через виртуальный коммутатор br-ch-os-fl
Итак, трафик попал в виртуальный коммутатор br-ch-os-fl
через физический интерфейс floating
(он же порт коммутатора с таким же именем floating
)
В отличии от "классических" коммутаторов, которые осуществляют пересылку пакетов основываясь на изученной таблице мак-адресов,
OpenFlow-коммутаторы (которыми и является виртуальный коммутатор br-ch-os-fl
)
используют для определения порта назначения OpenFlow-правила
Для просмотра правил в случае OpenVSwitch можно использовать команду ovs-ofctl dump-flows br-ch-os-fl
br-ch-os-fl
- это имя виртуального коммутатора, которых может быть более чем один на одной Linux-ноде.
Результат работы команды
cookie=0x2d19cd3395437eb3, duration=691002.184s, table=0, n_packets=106295, n_bytes=10732118, priority=2,in_port="phy-br-ch-os-fl" actions=resubmit(,1) cookie=0x2d19cd3395437eb3, duration=691222.458s, table=0, n_packets=186, n_bytes=11672, priority=0 actions=NORMAL cookie=0x2d19cd3395437eb3, duration=691002.076s, table=0, n_packets=777807, n_bytes=48652600, priority=1 actions=resubmit(,3) cookie=0x2d19cd3395437eb3, duration=691001.975s, table=1, n_packets=106295, n_bytes=10732118, priority=0 actions=resubmit(,2) cookie=0x2d19cd3395437eb3, duration=690851.627s, table=2, n_packets=105853, n_bytes=10694426, priority=4,in_port="phy-br-ch-os-fl",dl_vlan=2 actions=strip_vlan,NORMAL cookie=0x2d19cd3395437eb3, duration=691001.628s, table=2, n_packets=442, n_bytes=37692, priority=2,in_port="phy-br-ch-os-fl" actions=drop cookie=0x2d19cd3395437eb3, duration=690999.407s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:0e:d7:45 actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=690999.335s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:64:4e:1f actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=690999.291s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:96:cd:a5 actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=690999.111s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:a0:1e:1b actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=690998.887s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:f9:d4:00 actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=691001.561s, table=3, n_packets=777807, n_bytes=48652600, priority=1 actions=NORMAL
Правила просамтриваются в следующем порядке
- таблицы по номерам, первая таблица - с номером 0, если трафик не соответвует ни одному правилу то он отбрасывается
- Правила внутри таблицы просматриваются в порядке приоритетов, от большего к меньшему, первое правило с номером 65535
- При равном приортете правила просматриваются в том порядке в котором добавлены (c верху вниз)
Для лучшего понимания, отсортируем правила в то порядке в котором они будут работать
(с верху вниз, верхнее - первое)
Таблица 0
cookie=0x2d19cd3395437eb3, duration=691002.184s, table=0, n_packets=106295, n_bytes=10732118, priority=2,in_port="phy-br-ch-os-fl" actions=resubmit(,1) cookie=0x2d19cd3395437eb3, duration=691002.076s, table=0, n_packets=777807, n_bytes=48652600, priority=1 actions=resubmit(,3) cookie=0x2d19cd3395437eb3, duration=691222.458s, table=0, n_packets=186, n_bytes=11672, priority=0 actions=NORMAL
Таблица 1
cookie=0x2d19cd3395437eb3, duration=691001.975s, table=1, n_packets=106295, n_bytes=10732118, priority=0 actions=resubmit(,2)
Таблица 2
cookie=0x2d19cd3395437eb3, duration=690851.627s, table=2, n_packets=105853, n_bytes=10694426, priority=4,in_port="phy-br-ch-os-fl",dl_vlan=2 actions=strip_vlan,NORMAL cookie=0x2d19cd3395437eb3, duration=691001.628s, table=2, n_packets=442, n_bytes=37692, priority=2,in_port="phy-br-ch-os-fl" actions=drop
Таблица 3
cookie=0x2d19cd3395437eb3, duration=690999.407s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:0e:d7:45 actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=690999.335s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:64:4e:1f actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=690999.291s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:96:cd:a5 actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=690999.111s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:a0:1e:1b actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=690998.887s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:f9:d4:00 actions=output:"phy-br-ch-os-fl" cookie=0x2d19cd3395437eb3, duration=691001.561s, table=3, n_packets=777807, n_bytes=48652600, priority=1 actions=NORMAL
table 0
коммутатора br-ch-os-fl
Правила table 0
table=0, priority=2,in_port="phy-br-ch-os-fl" actions=resubmit(,1)
- Правило означает: все пакеты с порта
phy-br-ch-os-fl
, исследуемый трафик в это правило не попадает так как приходит с портаfloating
cookie=0x2d19cd3395437eb3, duration=691002.184s, table=0, n_packets=106295, n_bytes=10732118, priority=2,in_port="phy-br-ch-os-fl" actions=resubmit(,1)
table=0, priority=1 actions=resubmit(,3)
- Правило означает: все пакеты (так как не указано никакое условие) и именно оно будет применено к исследуемому трафику, действие в нет - перейти в таблицу 3, это действие описывает
actions=resubmit(,3)
cookie=0x2d19cd3395437eb3, duration=691002.076s, table=0, n_packets=777807, n_bytes=48652600, priority=1 actions=resubmit(,3)
table=0, priority=0 actions=NORMAL
- Это правило никогда не сработает, но если по какой-то причине предыдущее правило будет отсутствовать, то это правило заставит сделать коммутацию как классический свитч, используя таблицу ма-адресов.
cookie=0x2d19cd3395437eb3, duration=691222.458s, table=0, n_packets=186, n_bytes=11672, priority=0 actions=NORMAL
table 3
коммутатора br-ch-os-fl
Согласно правилу в таблице 0, исследуемый трафик отправлен в таблицу 3
В этой таблице много похожих правил, все они означают что при совпадении мак-адресов отправить пакет в порт phy-br-ch-os-fl
и ни один из мак-адресов не является мак-адресом трафика адресованного виртуальной машине
В случае когда трафик к виртуальной машине идет из-за пределов OpenStack (это и есть рассматриваемый случай), то мак-адресом отправителя таких пакетов будет мак-адрес маршрутизатора,
того интерфейса который смотрит в floating сеть (в этом сетапе это VLAN729)
Просмотреть мак-адрес в случае микротика можно в настройках интерфейса
/interface/bridge/print where name=bridge-mosk-vlan-729-ch-os-fl Flags: X - disabled, R - running 9 R name="bridge-mosk-vlan-729-ch-os-fl" mtu=auto actual-mtu=1500 l2mtu=1588 arp=enabled arp-timeout=auto mac-address=00:02:2D:AA:BB:02 protocol-mode=none fast-forward=yes igmp-snooping=no auto-mac=no admin-mac=00:02:2D:AA:BB:02 ageing-time=5m vlan-filtering=no dhcp-snooping=no
и тут видно что admin-mac=00:02:2D:AA:BB:02
не совпадает ни с одним из правил (все кроме первого правила спрятаны под спойлер), из чего делаем вывод что отрабатывает только последнее правило.
cookie=0x2d19cd3395437eb3, duration=690999.407s, table=3, n_packets=0, n_bytes=0, priority=2,dl_src=fa:16:3f:0e:d7:45 actions=output:"phy-br-ch-os-fl"
Последнее правило имеет actions=NORMAL
, это значит что дальнейшая коммутация будет осуществляться классическим способом, используя таблицу коммутации по мак-адресам,
и значит нужно проверить содержание этой таблицы.
cookie=0x2d19cd3395437eb3, duration=691001.561s, table=3, n_packets=777807, n_bytes=48652600, priority=1 actions=NORMAL
Forwarding Database
(таблица мак-адресов) коммутатора br-ch-os-fl
Таблицу Forwarding Database (FDB, таблица мак-адресов) на OpenVSwitch можно просмотреть командой:
ovs-appctl fdb/show br-ch-os-fl
port VLAN MAC Age 1 0 6a:7a:ba:bc:8b:26 219 1 0 d4:ca:6d:7c:a6:5c 199 1 0 52:54:15:aa:aa:16 24 1 0 52:54:15:ff:ff:16 23 1 0 00:02:2d:aa:bb:02 1 2 0 fa:16:3e:40:32:d5 1
Из этой таблицы видно, что целевой мак (fa:16:3e:40:32:d5
) в ней присутствует и изучен с порта номер 2,
а все остальные маки изучены с порта номер 1 (в том числе и мак маршрутизатора, 00:02:2d:aa:bb:02
)
Однако, вывод ovs-vsctl show
не дает информации о номерах портов, а только их имена:
Bridge br-ch-os-fl Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure datapath_type: system Port br-ch-os-fl Interface br-ch-os-fl type: internal Port phy-br-ch-os-fl Interface phy-br-ch-os-fl type: patch options: {peer=int-br-ch-os-fl} Port floating Interface floating
Далее требуется сопоставить номера портов виртуального коммутатора br-ch-os-fl
и их имена
Сопоставление номеров и имен портов для виртуального коммутатора br-ch-os-fl
Просмотреть нумерацию портов (внутри одного из многих коммутаторов!) можно командой
ovs-ofctl -OOpenFlow13 show br-ch-os-fl
br-ch-os-fl
- имя коммутатора, для которого хочется посмотреть порты
OFPT_FEATURES_REPLY (OF1.3) (xid=0x2): dpid:0000ba2f0edece4e n_tables:254, n_buffers:0 capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS OFPST_PORT_DESC reply (OF1.3) (xid=0x3): 1(floating): addr:52:54:15:ac:ac:16 config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max 2(phy-br-ch-os-fl): addr:96:e8:e7:04:ec:d9 config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max LOCAL(br-ch-os-fl): addr:ba:2f:0e:de:ce:4e config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max OFPT_GET_CONFIG_REPLY (OF1.3) (xid=0x9): frags=normal miss_send_len=0
Из вывода команды видно, что порт номер 2 это порт phy-br-ch-os-fl
, который имеет состояние LIVE
из вывода команды ovs-vsctl show
(оставлена только значимая часть) можно видеть что порт 2, он же phy-br-ch-os-fl
,
имеет тип type: patch
, и второй конец "виртуального патч-корда" имеет имя int-br-ch-os-fl
(options: {peer=int-br-ch-os-fl}
)
... Port phy-br-ch-os-fl Interface phy-br-ch-os-fl type: patch options: {peer=int-br-ch-os-fl} ...
TODO (открытые вопросы):
Пока не ясно для чего служит
LOCAL(br-ch-os-fl): addr:ba:2f:0e:de:ce:4e config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max
Этот же интерфейс, с таким же маком (ba:2f:0e:de:ce:4e
) и состоянием ( LINK_DOWN
) виден в системе:
ip link show dev br-ch-os-fl
77: br-ch-os-fl: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether ba:2f:0e:de:ce:4e brd ff:ff:ff:ff:ff:ff
Определение куда попадает трафик через виртуальный патчк-корд phy-br-ch-os-fl
Для того что бы понть куда трафик попадает через виртуальный патч-корд phy-br-ch-os-fl
, нужно
вернуться назад к выводу команды ovs-vsctl show
В части вывода, касающейся коммутатора br-int
можно видеть, что вторая часть патч-корда (peer=int-br-ch-os-fl
) является портом коммутатора br-int
Bridge br-int Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure datapath_type: system Port patch-tun Interface patch-tun type: patch options: {peer=patch-int} Port qr-e02600f1-cd tag: 1 Interface qr-e02600f1-cd type: internal Port int-br-ch-os-fl Interface int-br-ch-os-fl type: patch options: {peer=phy-br-ch-os-fl} Port qg-aefc8a2e-98 tag: 2 Interface qg-aefc8a2e-98 type: internal Port br-int Interface br-int type: internal Port qg-932d2f98-d2 tag: 2 Interface qg-932d2f98-d2 type: internal Port o-hm0 tag: 1 Interface o-hm0 type: internal Port fg-ecf7bdaf-ff tag: 2 Interface fg-ecf7bdaf-ff type: internal
Вот описание порта через который трафик попадет в коммутатор br-int
- это (ожидаемо) виртуальный патч-корд, второй конец которого - phy-br-ch-os-fl
включен в коммутатор br-ch-os-fl
Port int-br-ch-os-fl Interface int-br-ch-os-fl type: patch options: {peer=phy-br-ch-os-fl}
Прохождение трафика через виртуальный коммутатор br-int
Как выяснили, трафик попадает в коммутатор br-int
через порт int-br-ch-os-fl
Port int-br-ch-os-fl Interface int-br-ch-os-fl type: patch options: {peer=phy-br-ch-os-fl}
Так-как коммутатор br-int
так же являетя OpenFlow коммутатором, то для понимания пути прохождения трафика нужно просмотреть правила OpenFlow
Просмотреть правила можно командой:
ovs-ofctl dump-flows br-int
Полный вывод достаточно большой, скрыт под спойлер, для анализа используем сокращенный вывод.
В целом логика такая же как и при прохождении трафика br-ch-os-fl
Напомню, чтот правила просматриваются по таблицам, сначала таблица 0, потом 1 и т.д, а правила внутри таблицы просматриваются в порядке приоритета, от большего к меньшему
Далее везде используется вывод уже отсортированный для удобства просмотра.
Поля
cookie
,
duration
,
n_packets
n_bytes
удалены для удобства, они не влияют на результат работы правила.
table 0
коммутатора br-int
table=0 priority=65535,dl_vlan=4095
Этому правилу (ниже) соответствует трафик с VLAN_ID=4095, рассматриваемый сейчас трафик тэга не имеет, значит правило не срабатывает на него.
table=0 priority=65535,dl_vlan=4095 actions=drop
table=0 priority=200,reg3=0
Это правило (ниже) вызывает у меня затруднение, reg3=0
это обращение к 3-му регистру, но я пока не могу точно сказать как работает это расширение протокола OpenFlow
Судя по всему, это правило следует читать так
Если у пакета регистр3=0 (что касается всех пакетов, так как этот регистр - это внутреннее свойство пакета, а не поле по какому-либо смещению, и не существует за пределами OpenVSwitch), то:
set_queue:0,load
Установить очередь 0 (TODO: Добавить пояснения)0x1->NXM_NX_REG3[0]
Установить (загрузить в регистр) значение 0x1 в 0 байт регистра 3resubmit(,0)
Перенаправить пакет на вход таблицы 0
При повторном прохождении пакета это правило более не срабатывает, так как reg3 не равен более 0, а равен 0x1
table=0 priority=200,reg3=0 actions=set_queue:0,load:0x1->NXM_NX_REG3[0],resubmit(,0)
table=0 priority=5,in_port="int-br-ch-os-fl",dl_dst=fa:16:3f:e0:b7:4b actions=resubmit(,4)
Это правило (ниже) не срабатывает так-как не совпадает мак получателя (мак получателя FA:16:3E:40:32:D5
не совпадает с маком fa:16:3f:e0:b7:4b
из правила)
table=0 priority=5,in_port="int-br-ch-os-fl",dl_dst=fa:16:3f:e0:b7:4b actions=resubmit(,4)
Остальные не сработавшие но полностью аналогичные правила спрятаны под спойлер, мак-адреса тоже не совпадают.
table=0 priority=3,in_port="int-br-ch-os-fl",vlan_tci=0x0000/0x1fff actions=mod_vlan_vid:2,resubmit(,60)
Это правило следует читать как
- Пакеты с порта
int-br-ch-os-fl
- У которых не установлен VlanID
Чуть подробнее остановлюсь на условии vlan_tci=0x0000/0x1fff
Прочитать можно тут: ovs-fields.7.txt
Правило читается так:
- взять поле
vlan_tci
(это внутренняя структура у OpenVSwitchи других OpenFlow свитчей, а не поле в пакете!) - наложить на него битовую маску
0x1fff
(что в двоичной форме соответствует0001111111111111
- результат сравнить с 0x0000
Накладывание битовой маски - по сути операция умножения, другим словами это означает что первые три бита в исходном пакет могут быть любыми (после умножения на 0 они будут равны 0),
а остальные должны уже быть равны нулю в исходном пакете (умножение на 1 не изменяет их значения)
В описании поля vlan_tci
видно, что первые 3 бита отведены под PCP (Priority Control Point)
NXM_VLAN_TCI <----------> 3 1 12 +----+--+----+ |PCP |P |VID | +----+--+----+
Другими словами, это правило означает что
- Бит присутствия VLAN (CFI, Canonical Format Indicator) должен быть выставлен в 0
- Поле VLAN ID выставлено в 0 (все биты установлены в 0)
- значение поля приоритета игнорируетс
В сумме это правило значит "нетэгированный пакет с порта int-br-ch-os-fl
" куда и попадает искомый трафик - и он далее передается в таблицу 60 после того как на него будет добавлен тег 2 (mod_vlan_vid:2
)
table=0 priority=3,in_port="int-br-ch-os-fl",vlan_tci=0x0000/0x1fff actions=mod_vlan_vid:2,resubmit(,60)
table=0 priority=2,in_port="int-br-ch-os-fl" actions=drop
Это правило значит что все что не попало под предыдущее правило (другими словами пакеты с тегом) нужно дропнуть
table=0 priority=2,in_port="int-br-ch-os-fl" actions=drop
table=0 priority=0 actions=resubmit(,60)
Это правило безусловно все остальные пакеты передаст в таблицу 60, не модифицируя их
table=0 priority=0 actions=resubmit(,60)
table 60
коммутатора br-int
Полный список правил (вывод не содержит не значазих полей)
table=60 priority=100,in_port="o-hm0" actions=load:0x3->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],resubmit(,71) table=60 priority=100,in_port="qg-aefc8a2e-98" actions=load:0x6->NXM_NX_REG5[],load:0x2->NXM_NX_REG6[],resubmit(,73) table=60 priority=100,in_port="qg-932d2f98-d2" actions=load:0x7->NXM_NX_REG5[],load:0x2->NXM_NX_REG6[],resubmit(,73) table=60 priority=100,in_port="fg-ecf7bdaf-ff" actions=load:0x5->NXM_NX_REG5[],load:0x2->NXM_NX_REG6[],resubmit(,73) table=60 priority=100,in_port="qr-e02600f1-cd" actions=load:0x4->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],resubmit(,73) table=60 priority=90,dl_vlan=1,dl_dst=fa:16:3e:0c:e4:73 actions=load:0x3->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],strip_vlan,resubmit(,81) table=60 priority=3 actions=NORMAL
Тут видно что все правила, кроме последнего, имеют условия не соответствующие исследуемому трафику - отличия в поле in_port
, vlan или мак
Соответственно срабатывает третье правило (actions=NORMAL
) и далее для коммутации трафика используется классическаая таблица мак-адресов
Таблица мак-адресов коммутатора br-int
Далее для проверки куда отправить пакет с маком назначения fa:16:3e:40:32:d5
нужно проверить содержимое таблицы коммутации (FDB, Forwarding Database)
ovs-appctl fdb/show br-int
port VLAN MAC Age 1 2 52:54:15:aa:aa:16 119 1 2 52:54:15:ff:ff:16 38 1 2 00:02:2d:aa:bb:02 0 5 2 fa:16:3e:40:32:d5 0
Тут видно что мак fa:16:3e:40:32:d5
изучен с порта номер 5
Для того что бы выяснить какой именно порт имеет номер 5, просмотреть номера портов
ovs-ofctl -OOpenFlow13 show br-int
OFPT_FEATURES_REPLY (OF1.3) (xid=0x2): dpid:0000ae845ebd9a43 n_tables:254, n_buffers:0 capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS OFPST_PORT_DESC reply (OF1.3) (xid=0x3): 1(int-br-ch-os-fl): addr:f6:69:e1:c0:39:3c config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max 2(patch-tun): addr:16:6a:e5:70:65:5c config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max 3(o-hm0): addr:fa:16:3e:42:68:31 config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max 4(qr-e02600f1-cd): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max 5(qg-aefc8a2e-98): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max 6(fg-deee2f23-09): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max 7(qg-932d2f98-d2): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max 8(tapb9b0014b-e1): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max LOCAL(br-int): addr:ae:84:5e:bd:9a:43 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max OFPT_GET_CONFIG_REPLY (OF1.3) (xid=0x9): frags=normal miss_send_len=0
Тут видно что номеру 5 соответствует интерфейс qg-aefc8a2e-98
5(qg-aefc8a2e-98): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max
ovs-vsctl show
показывает что
- это интерфейс типа
internal
и это означает что он должен быть виден в системе командойip link show ...
- этот интерфейс имеет VLAN (
tag: 2
), что (предположительно) соответствует access port 2, при отправки на этот порт будет снят тег, а при получении - добавлен тег 2 - тег 2 совпадает с тегом которым тегирован исследуемый трафик
Port qg-932d2f98-d2 tag: 2 Interface qg-932d2f98-d2 type: internal </code> Однако "в лоб" интерфейс в системе не виден <BR> <code>ip link show dev qg-aefc8a2e-98</code> <PRE> Device "qg-aefc8a2e-98" does not exist.
Это связано с тем что он находится внутри network namespace
Дальнейшим прохождением трафика занимается уже не OpenVSwitch, а сетевая подсистема Linux
Можно было увидеть: config: PORT_DOWN
, state: LINK_DOWN
5(qg-aefc8a2e-98): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max
Могу предположить что OpenVSWitch не может определить статус интерфейса, если он находится в network namespace отличном от "умолчального" (в терминах Cisco это называется VRF Global)
Прохождение трафика внутри Network Node
Первым делом следует определить в какой именно network namespace помещен интерфейс (qg-aefc8a2e-98
- имя интерфейса и оно же имя порта openvswitch)
Определение Network Namespace в который попадает трафик
ip netns list
qdhcp-bd7e52d9-e09c-4d43-8816-db1be731a761 (id: 50) fip-5b1a5b04-b5ed-4ced-a097-585f40b0a5fd (id: 29) snat-6cf2a3cc-5242-42b5-8c57-3ee78b0d0983 (id: 49) qrouter-6cf2a3cc-5242-42b5-8c57-3ee78b0d0983 qrouter-54550846-33f2-4954-8649-3233a49cedb4 (id: 14)
Для того что бы не перебирать все неймспейсы руками:
for NET_NS_NAME in $(ip netns list | awk '{print $1}'); do ip netns exec ${NET_NS_NAME} ip -s -d link show dev qg-aefc8a2e-98 2>/dev/null && echo ${NET_NS_NAME} && break; done
83: qg-aefc8a2e-98: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/ether fa:16:3e:40:32:d5 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65535 openvswitch addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 RX: bytes packets errors dropped overrun mcast 373294 7318 0 0 0 0 TX: bytes packets errors dropped carrier collsns 198624 1955 0 0 0 0 qrouter-54550846-33f2-4954-8649-3233a49cedb4
Из вывода видно, что интерфейс это порт openvswitch
,
а искомый Network Namespace - qrouter-54550846-33f2-4954-8649-3233a49cedb4
На самом деле можно было предположить что это какой-то роутер
openstack router list
+--------------------------------------+------+--------+-------+----------------------------------+-------------+-------+ | ID | Name | Status | State | Project | Distributed | HA | +--------------------------------------+------+--------+-------+----------------------------------+-------------+-------+ | 54550846-33f2-4954-8649-3233a49cedb4 | r2 | ACTIVE | UP | 93900840d7804fd2adfe9bfd452263c7 | False | False | ...
и тут видно что ID роутера совпадает с именем неймспейса
Конечно когда роутеров много - все может оказаться сложнее
qrouter-54550846-33f2-4954-8649-3233a49cedb4
Далее запускаем шелл (отключив буфферизацию ввода и вывода и исследуем настройки сети внутри неймспейса)
ip netns exec qrouter-54550846-33f2-4954-8649-3233a49cedb4 stdbuf -i0 -o0 -e0 bash
tcpdump
выдает на экран пакеты не сразу, а пачками. Что может сильно мешать дебагуПричины такого поведения в неймспейсе я пока не исследовал
Просмотрим базовые настойки сетевого стека:
ip -d link show
ip -d 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 promiscuity 0 minmtu 0 maxmtu 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 82: qr-e02600f1-cd: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1430 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/ether fa:16:3e:69:cd:07 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65535 openvswitch addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 83: qg-aefc8a2e-98: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/ether fa:16:3e:40:32:d5 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65535 openvswitch addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
Из вывода можно увидеть, что тут присутвуют 2 интерфейса, оба являются портами OpenVSwitch:
qg-aefc8a2e-98
- интерфейс через который приходит трафикqr-e02600f1-cd
- еще один интерфейс, назначение которого пока не известно (но можно предположить что он смотрит во внутреннюю сеть тенанта)
Роутер выглядит как классический, с 1 портом WAN - qg-aefc8a2e-98 и одним портом LAN - qr-e02600f1-cd
ip -d addr show
ip -d addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 minmtu 0 maxmtu 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 82: qr-e02600f1-cd: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1430 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether fa:16:3e:69:cd:07 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65535 openvswitch numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 inet 10.255.0.1/16 brd 10.255.255.255 scope global qr-e02600f1-cd valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe69:cd07/64 scope link valid_lft forever preferred_lft forever 83: qg-aefc8a2e-98: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether fa:16:3e:40:32:d5 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65535 openvswitch numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 inet 10.72.10.27/24 brd 10.72.10.255 scope global qg-aefc8a2e-98 valid_lft forever preferred_lft forever inet 10.72.10.124/32 brd 10.72.10.124 scope global qg-aefc8a2e-98 valid_lft forever preferred_lft forever inet6 fe80::f816:3eff:fe40:32d5/64 scope link valid_lft forever preferred_lft forever
У роутера 3 IP адреса (за исклбючением lo который я нигде отдельно не описываю)
- на интерфейсе
qg-aefc8a2e-98
10.255.0.1/16
- это адрес на интерфейсе в тенантную сеть и он выступает шлюзом для ВМ в этой сети
- на интерфейсе
qg-aefc8a2e-98
10.72.10.27/24
- Floating IP роутера (кстати зачем он ему?)10.72.10.124/32
- Floating IP назначеный на ВМ
Так как Floating адрес виртуальной машины назначин на интерфейс qg-aefc8a2e-98
, который как рассмотрели выше, средствами OpenVSwitch,
через виртуальные коммутаторы соединен с сетью floating (Vlan729 на физическом коммутаторе), то становится понятно как происходит изучение ARP -
сетевой стек линукса Network Node отвечает на ARP-запросы на адрес 10.72.10.124, что является поведением по-умолчанию.
Никакая "магия" proxy_arp здесь не используется
В целом точно такой же результат можно было бы получить если бы вместо порта OpenVSwitch использовать физический интерфейс и включить его во VLAN729.
(это удобно для представления в голове как проходит трафик, как некое урощение, но очевидо физических сетевых карт не может быть слишком много в сервере, а виртуальных маршрутизаторов может быть
практически не ограниченное колличество, по-тому ни о каком использовании реальных карт не модет быть и речи - только порты виртуального коммутатора)
ip route
ip route
default via 10.72.10.1 dev qg-aefc8a2e-98 proto static 10.72.10.0/24 dev qg-aefc8a2e-98 proto kernel scope link src 10.72.10.27 10.255.0.0/16 dev qr-e02600f1-cd proto kernel scope link src 10.255.0.1
Таблица маршрутизации соответствует ожиданиям и максимально проста - по одному маршруту в каждый из сегментов сети, и маршрут по-умолчанию.
arp -n
arp -n
arp -n Address HWtype HWaddress Flags Mask Iface 10.255.4.184 ether fa:16:3e:ea:49:b7 C qr-e02600f1-cd 10.72.10.1 ether 00:02:2d:aa:bb:02 C qg-aefc8a2e-98
Таблица ARP тоже полностью соответвует ожиданиям - 2 записи, шлюза во внешний мир и виртуальной машины.
ip route get 10.72.10.124
ip route get 10.72.10.124
ip route get 10.72.10.124 local 10.72.10.124 dev lo src 10.72.10.124 uid 0 cache <local>
Результат соответвует ожиданиям - так как адрес 10.72.10.124
назначен на один из интерфейса маршрутизатора, то трафик адресованный этому адресу (тавтология?) будет обрабатываться как локальный.
iptables-save
iptables-save
*raw
# Generated by iptables-save v1.8.4 on Mon Apr 17 11:54:58 2023 *raw :PREROUTING ACCEPT [2580:169942] :OUTPUT ACCEPT [2537:233396] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-PREROUTING - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A OUTPUT -j neutron-l3-agent-OUTPUT COMMIT # Completed on Mon Apr 17 11:54:58 2023 # Generated by iptables-save v1.8.4 on Mon Apr 17 11:54:58 2023
*nat
*nat :PREROUTING ACCEPT [11:2391] :INPUT ACCEPT [11:2391] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [2:128] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-POSTROUTING - [0:0] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-float-snat - [0:0] :neutron-l3-agent-snat - [0:0] :neutron-postrouting-bottom - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A OUTPUT -j neutron-l3-agent-OUTPUT -A POSTROUTING -j neutron-l3-agent-POSTROUTING -A POSTROUTING -j neutron-postrouting-bottom -A neutron-l3-agent-OUTPUT -d 10.72.10.124/32 -j DNAT --to-destination 10.255.4.184 -A neutron-l3-agent-POSTROUTING ! -o qg-aefc8a2e-98 -m conntrack ! --ctstate DNAT -j ACCEPT -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697 -A neutron-l3-agent-PREROUTING -d 10.72.10.124/32 -j DNAT --to-destination 10.255.4.184 -A neutron-l3-agent-float-snat -s 10.255.4.184/32 -j SNAT --to-source 10.72.10.124 --random-fully -A neutron-l3-agent-snat -j neutron-l3-agent-float-snat -A neutron-l3-agent-snat -m mark ! --mark 0x2/0xffff -m conntrack --ctstate DNAT -j SNAT --to-source 10.72.10.27 --random-fully -A neutron-postrouting-bottom -m comment --comment "Perform source NAT on outgoing traffic." -j neutron-l3-agent-snat COMMIT # Completed on Mon Apr 17 11:54:58 2023 # Generated by iptables-save v1.8.4 on Mon Apr 17 11:54:58 2023
*mangle
:PREROUTING ACCEPT [2580:169942] :INPUT ACCEPT [12:2739] :FORWARD ACCEPT [32:4899] :OUTPUT ACCEPT [2537:233396] :POSTROUTING ACCEPT [2569:238295] :neutron-l3-agent-FORWARD - [0:0] :neutron-l3-agent-INPUT - [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-POSTROUTING - [0:0] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-float-snat - [0:0] :neutron-l3-agent-floatingip - [0:0] :neutron-l3-agent-mark - [0:0] :neutron-l3-agent-scope - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A INPUT -j neutron-l3-agent-INPUT -A FORWARD -j neutron-l3-agent-FORWARD -A OUTPUT -j neutron-l3-agent-OUTPUT -A POSTROUTING -j neutron-l3-agent-POSTROUTING -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-mark -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-scope -A neutron-l3-agent-PREROUTING -m connmark ! --mark 0x0/0xffff0000 -j CONNMARK --restore-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-floatingip -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x1/0xffff -A neutron-l3-agent-float-snat -m connmark --mark 0x0/0xffff0000 -j CONNMARK --save-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-mark -i qg-aefc8a2e-98 -j MARK --set-xmark 0x2/0xffff -A neutron-l3-agent-scope -i qr-e02600f1-cd -j MARK --set-xmark 0x4000000/0xffff0000 -A neutron-l3-agent-scope -i qg-aefc8a2e-98 -j MARK --set-xmark 0x4000000/0xffff0000 COMMIT # Completed on Mon Apr 17 11:54:58 2023 # Generated by iptables-save v1.8.4 on Mon Apr 17 11:54:58 2023
*filter
:INPUT ACCEPT [12:2739] :FORWARD ACCEPT [32:4899] :OUTPUT ACCEPT [2537:233396] :neutron-filter-top - [0:0] :neutron-l3-agent-FORWARD - [0:0] :neutron-l3-agent-INPUT - [0:0] :neutron-l3-agent-OUTPUT - [0:0] :neutron-l3-agent-local - [0:0] :neutron-l3-agent-scope - [0:0] -A INPUT -j neutron-l3-agent-INPUT -A FORWARD -j neutron-filter-top -A FORWARD -j neutron-l3-agent-FORWARD -A OUTPUT -j neutron-filter-top -A OUTPUT -j neutron-l3-agent-OUTPUT -A neutron-filter-top -j neutron-l3-agent-local -A neutron-l3-agent-FORWARD -j neutron-l3-agent-scope -A neutron-l3-agent-INPUT -m mark --mark 0x1/0xffff -j ACCEPT -A neutron-l3-agent-INPUT -p tcp -m tcp --dport 9697 -j DROP -A neutron-l3-agent-scope -o qr-e02600f1-cd -m mark ! --mark 0x4000000/0xffff0000 -j DROP -A neutron-l3-agent-scope -o qg-aefc8a2e-98 -m mark ! --mark 0x4000000/0xffff0000 -j DROP COMMIT # Completed on Mon Apr 17 11:54:58 2023
Разбор правил IPTABLES
На первый взгляд правил довольно много
Для понимания в каком порядке происходит прохождения пакета - прикрепляю классическую 'iptables-big-picture' (так она и назодится гуглом)
]
Из этой схемы становится более понятно в каком порядке какие таблицы просматривать.
eBPF/qdisc (шейпера) пропускаем. Считаем что интерфейс не является бриджом (в классическом смысле - Linux Bridge, проверить brctl show
, которая показывает что бриджей нет)
Порядок прохождения пакетов
Имя таблицы | Имя Цепочки | Примечание | Примечание 2 |
---|---|---|---|
raw | PREROUTING |
*raw :PREROUTING ACCEPT [2580:169942] :neutron-l3-agent-PREROUTING - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING |
В таблице raw в цепочке PREROUTING только одно правило, пересылает пакеты в цепочку |
mangle | PREROUTING |
:PREROUTING ACCEPT [2580:169942] :neutron-l3-agent-PREROUTING - [0:0] :neutron-l3-agent-floatingip - [0:0] -A PREROUTING -j neutron-l3-agent-PREROUTING -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-mark -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-scope -A neutron-l3-agent-PREROUTING -m connmark ! --mark 0x0/0xffff0000 -j CONNMARK --restore-mark --nfmask 0xffff0000 --ctmask 0xffff0000 -A neutron-l3-agent-PREROUTING -j neutron-l3-agent-floatingip -A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x1/0xffff |
111
|
nat | PREROUTING | ||
Принятие решения о маршрутизации | |||
mangle | FORWARD | ||
filter | FORWARD | ||
mangle | POSTROUTING | ||
nat | POSTROUTING |
!!!!Раздел не закончен!!!!!
-A neutron-l3-agent-PREROUTING -d 10.72.10.124/32 -j DNAT --to-destination 10.255.4.184
Вот это правило - меняет в заголовке назначение пакета с адреса 10.72.10.124
(это и есть адрес Floating IP) на адрес сервера 10.255.4.184
После чего пакет передается процессу маршрутизации
Маршрутизация
Пакет дальше маршрутизируется с новым адресаом получателя - 10.255.4.184
, соответвенно можно проверить таблицу маршрутизации для этого адреса назначения:
ip ro get 10.255.4.184
10.255.4.184 dev qr-e02600f1-cd src 10.255.0.1 uid 0 cache
Отсюда видно что пакет будет отправлен через интерфейс dev qr-e02600f1-cd
Подробнее информация об интерфейсе qr-e02600f1-cd
:
ip -d link show dev qr-e02600f1-cd
82: qr-e02600f1-cd: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1430 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/ether fa:16:3e:69:cd:07 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65535 openvswitch addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
Тут видно что этот интерфейс - порт openvswitch
, другими словами пакет после процесса маршрутизации снова попадает в виртуальный коммутатор.
ВАЖНО: Пакет уже модифицирован - он имеет другой адрес получателя и другой МАК-адрес:
arp -n 10.255.4.184
Address HWtype HWaddress Flags Mask Iface 10.255.4.184 ether fa:16:3e:ea:49:b7 C qr-e02600f1-cd
НОВЫЙ Мак-адрес: fa:16:3e:ea:49:b7
Прохождение трафика внутри OpenVSwitch (после процесса маршрутизации)
Повторно пакет в OpenVSwitch попадает через интерфейс qr-e02600f1-cd
Просмотрев командой ovs-vsctl show
конфигурацию, можно увидеть порт свитча соответвующий интерфейсу:
Port qr-e02600f1-cd tag: 1 Interface qr-e02600f1-cd type: internal
Этот порт является портом свитча br-int
.
Bridge br-int Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure datapath_type: system Port qg-932d2f98-d2 tag: 2 Interface qg-932d2f98-d2 type: internal Port br-int Interface br-int type: internal Port int-br-ch-os-fl Interface int-br-ch-os-fl type: patch options: {peer=phy-br-ch-os-fl} Port patch-tun Interface patch-tun type: patch options: {peer=patch-int} Port fg-deee2f23-09 tag: 2 Interface fg-deee2f23-09 type: internal Port qr-e02600f1-cd tag: 1 Interface qr-e02600f1-cd type: internal Port o-hm0 tag: 1 Interface o-hm0 type: internal Port tapb9b0014b-e1 tag: 1 Interface tapb9b0014b-e1 type: internal Port qg-aefc8a2e-98 tag: 2 Interface qg-aefc8a2e-98 type: internal
Далее снова следует вернуться к OpenFlow правилам коммутатора br-int
Таблицы коммутатора br-int
Для простоты просмотра вырежем из вывода счетчики и прочие поля которые не влияют на коммутацию пакета:
ovs-ofctl dump-flows br-int | awk '{print $3" "$6" "$7}' | column -t
Вывод выглядит так (2 строки для примера)
table=0, priority=65535,dl_vlan=4095 actions=drop table=0, priority=200,reg3=0 actions=set_queue:0,load:0x1->NXM_NX_REG3[0],resubmit(,0)
Для сравнения полный вывод без форматирования:
cookie=0xe00566add900f16d, duration=4675.255s, table=0, n_packets=0, n_bytes=0, priority=65535,dl_vlan=4095 actions=drop cookie=0x8777a5187aa1b046, duration=4673.509s, table=0, n_packets=26045, n_bytes=2256052, priority=200,reg3=0 actions=set_queue:0,load:0x1->NXM_NX_REG3[0],resubmit(,0)
Поля,которые не интересуют для анализа прохождения пакета и вырезаны:
- cookie
- duration
- n_packets
- n_bytes
Далее проджолжаем анализ по-таблично, от таблицы с номером 0, внутри таблицы правила идут в порядке приоритетов, от большего к меньшему
table0
коммутатора br-int
(второй проход)
table 0
table=0, priority=65535,dl_vlan=4095 actions=drop table=0, priority=200,reg3=0 actions=set_queue:0,load:0x1->NXM_NX_REG3[0],resubmit(,0) table=0, priority=5,in_port="int-br-ch-os-fl",dl_dst=fa:16:3f:e0:b7:4b actions=resubmit(,4) table=0, priority=5,in_port="patch-tun",dl_dst=fa:16:3f:e0:b7:4b actions=resubmit(,3) table=0, priority=4,in_port="int-br-ch-os-fl",dl_src=fa:16:3f:0e:d7:45 actions=resubmit(,2) table=0, priority=4,in_port="int-br-ch-os-fl",dl_src=fa:16:3f:38:c0:62 actions=resubmit(,2) table=0, priority=4,in_port="int-br-ch-os-fl",dl_src=fa:16:3f:64:4e:1f actions=resubmit(,2) table=0, priority=4,in_port="int-br-ch-os-fl",dl_src=fa:16:3f:96:cd:a5 actions=resubmit(,2) table=0, priority=4,in_port="int-br-ch-os-fl",dl_src=fa:16:3f:a0:1e:1b actions=resubmit(,2) table=0, priority=4,in_port="int-br-ch-os-fl",dl_src=fa:16:3f:f9:d4:00 actions=resubmit(,2) table=0, priority=2,in_port="patch-tun",dl_src=fa:16:3f:0e:d7:45 actions=resubmit(,1) table=0, priority=2,in_port="patch-tun",dl_src=fa:16:3f:38:c0:62 actions=resubmit(,1) table=0, priority=2,in_port="patch-tun",dl_src=fa:16:3f:64:4e:1f actions=resubmit(,1) table=0, priority=2,in_port="patch-tun",dl_src=fa:16:3f:96:cd:a5 actions=resubmit(,1) table=0, priority=2,in_port="patch-tun",dl_src=fa:16:3f:a0:1e:1b actions=resubmit(,1) table=0, priority=2,in_port="patch-tun",dl_src=fa:16:3f:f9:d4:00 actions=resubmit(,1) table=0, priority=3,in_port="int-br-ch-os-fl",vlan_tci=0x0000/0x1fff actions=mod_vlan_vid:2,resubmit(,60) table=0, priority=2,in_port="int-br-ch-os-fl" actions=drop table=0, priority=0 actions=resubmit(,60)
Тут можно видеть, что ни одно правило не имеет fl_dst=fa:16:3e:ea:49:b7
, где мак fa:16:3e:ea:49:b7 это мак виртуальной машины
(отличный от оригинального мака, так как пакет был отмаршрутизирован, и соответвенно мак получателя изменен)
Остальные правила кроме table=0, priority=200,reg3=0 actions=set_queue:0,load:0x1->NXM_NX_REG3[0],resubmit(,0)
которое устанавливает значение регистра reg3 (ВНУТРЕННИЙ регистр, модификация пакета НЕ происходит!)
не соответвуют пакету, и последним правилом table=0, priority=0 actions=resubmit(,60)
пакет отправляется в таблицу 60
table 60
коммутатора br-int
(второй проход)
table 60
table=60, priority=100,in_port="o-hm0" actions=load:0x3->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],resubmit(,71) table=60, priority=100,in_port="qg-aefc8a2e-98" actions=load:0x6->NXM_NX_REG5[],load:0x2->NXM_NX_REG6[],resubmit(,73) table=60, priority=100,in_port="qr-e02600f1-cd" actions=load:0x5->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],resubmit(,73) table=60, priority=100,in_port="tap0692f9f3-7f" actions=load:0x4->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],resubmit(,73) table=60, priority=90,dl_vlan=1,dl_dst=fa:16:3e:0c:e4:73 actions=load:0x3->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],strip_vlan,resubmit(,81) table=60, priority=3 actions=NORMAL
Как было выяснено выше, пакет к коммутатор попадает через порт qr-e02600f1-cd
и имеет мак назначения fa:16:3e:ea:49:b7
Просмотрев таблицу 60 сразу видно, что единственно правило которому соответвует пакет это
table=60, priority=100,in_port="qr-e02600f1-cd" actions=load:0x5->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],resubmit(,73)
Согласно этому правилу, производятся следующие действия:
load:0x5->NXM_NX_REG5[]
- записать значение 0x5 в регистр 5load:0x1->NXM_NX_REG6[]
- записать значение 0x1 в регистр 6resubmit(,73)
- передать пакет в таблицу 73
table 73
коммутатора br-int
table 73 Пакет имеет мак назначения fa:16:3e:ea:49:b7, reg5=0x5, reg6=0x1
table=73, priority=100,reg6=0x1,dl_dst=fa:16:3e:0c:e4:73 actions=load:0x3->NXM_NX_REG5[],resubmit(,81) table=73, priority=90,ct_state=+new-est,ip,reg5=0x3 actions=ct(commit,zone=NXM_NX_REG6[0..15]),resubmit(,91) table=73, priority=90,ct_state=+new-est,ipv6,reg5=0x3 actions=ct(commit,zone=NXM_NX_REG6[0..15]),resubmit(,91) table=73, priority=80,reg5=0x3 actions=resubmit(,94) table=73, priority=80,reg5=0x6 actions=resubmit(,94) table=73, priority=80,reg5=0x5 actions=resubmit(,94) table=73, priority=80,reg5=0x4 actions=resubmit(,94) table=73, priority=0 actions=drop
Единсственное правило, которому соответвует пакет - это table=73, priority=80,reg5=0x4 actions=resubmit(,94)
,
согласно которому пакет попадает в таблицу 94
table 94
коммутатора br-int
table 94
table=94, priority=1 actions=NORMAL
Единственное правило говорит о том, что дальнейшая коммутация осуществляется на основе классической таблицы коммутации (Forwarding database, FDB)
Таблица мак-адресов коммутатора br-int (второй проход)
Мак-адрес назначения в пакете - fa:16:3e:ea:49:b7
ovs-appctl fdb/show br-int
port VLAN MAC Age 1 2 52:54:15:bb:bb:16 118 2 1 fa:16:3e:ea:49:b7 1 1 2 00:02:2d:aa:bb:02 1 5 1 fa:16:3e:69:cd:07 1 6 2 fa:16:3e:40:32:d5 1 1 2 52:54:15:ff:ff:16 1 1 2 52:54:15:aa:aa:16 1
Тут видно, что мак-адрес назначения (fa:16:3e:ea:49:b7 )встречается 1 раз - в строке
2 1 fa:16:3e:ea:49:b7 1
Соответственно порт назначения имеет номер 2.
Для того что бы выяснить какой именно порт имеет номер 2, просмотреть номера портов
ovs-ofctl -OOpenFlow13 show br-int
OFPT_FEATURES_REPLY (OF1.3) (xid=0x2): dpid:0000ae03d42a2e4e n_tables:254, n_buffers:0 capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS OFPST_PORT_DESC reply (OF1.3) (xid=0x3): 1(int-br-ch-os-fl): addr:8a:38:2d:a7:77:0a config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max 2(patch-tun): addr:6a:2a:dd:60:81:7c config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max 3(o-hm0): addr:fa:16:3e:0c:e4:73 config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max 4(tap0692f9f3-7f): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max 5(qr-e02600f1-cd): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max 6(qg-aefc8a2e-98): addr:00:00:00:00:00:00 config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max LOCAL(br-int): addr:ae:03:d4:2a:2e:4e config: PORT_DOWN state: LINK_DOWN speed: 0 Mbps now, 0 Mbps max OFPT_GET_CONFIG_REPLY (OF1.3) (xid=0x9): frags=normal miss_send_len=0
Тут видно, что порт с номером 2 это
2(patch-tun): addr:6a:2a:dd:60:81:7c config: 0 state: LIVE speed: 0 Mbps now, 0 Mbps max
Что это за порт можно найти в выводе команды ovs-vsctl show
Port patch-tun Interface patch-tun type: patch options: {peer=patch-int}
Этот порт имеет тип patch
, другими словами соединяет 2 виртуальных коммутатора,
и просмотрев вывод команды
ovs-vsctl show
можно найти второй конец этого виртуального патч-корда, и увидеть что он включен в Bridge br-tun
Port patch-int Interface patch-int type: patch options: {peer=patch-tun}
Полностью информация о виртуальном коммутаторе br-tun
Bridge br-tun Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure datapath_type: system Port vxlan-0a48080a Interface vxlan-0a48080a type: vxlan options: {df_default="true", dst_port="4790", egress_pkt_mark="0", in_key=flow, local_ip="10.72.8.9", out_key=flow, remote_ip="10.72.8.10"} Port vxlan-0a48080b Interface vxlan-0a48080b type: vxlan options: {df_default="true", dst_port="4790", egress_pkt_mark="0", in_key=flow, local_ip="10.72.8.9", out_key=flow, remote_ip="10.72.8.11"} Port vxlan-0a48080d Interface vxlan-0a48080d type: vxlan options: {df_default="true", dst_port="4790", egress_pkt_mark="0", in_key=flow, local_ip="10.72.8.9", out_key=flow, remote_ip="10.72.8.13"} Port br-tun Interface br-tun type: internal Port patch-int Interface patch-int type: patch options: {peer=patch-tun}
Дальнейшая коммутация пакета будет выполняться коммутатором br-tun
Прохождение трафика через виртуальный коммутатор br-tun
Как выяснили, трафик попадает в коммутатор br-tun
через порт patch-int
111
Для простоты просмотра вырежем из вывода счетчики и прочие поля которые не влияют на коммутацию пакета:
ovs-ofctl dump-flows br-int | awk '{print $3" "$6" "$7}' | column -t
Вывод выглядит так (2 строки для примера)
table=0, priority=65535,dl_vlan=4095 actions=drop table=0, priority=200,reg3=0 actions=set_queue:0,load:0x1->NXM_NX_REG3[0],resubmit(,0)
Для сравнения полный вывод без форматирования:
cookie=0xe00566add900f16d, duration=4675.255s, table=0, n_packets=0, n_bytes=0, priority=65535,dl_vlan=4095 actions=drop cookie=0x8777a5187aa1b046, duration=4673.509s, table=0, n_packets=26045, n_bytes=2256052, priority=200,reg3=0 actions=set_queue:0,load:0x1->NXM_NX_REG3[0],resubmit(,0)
Поля,которые не интересуют для анализа прохождения пакета и вырезаны:
- cookie
- duration
- n_packets
- n_bytes
Далее проджолжаем анализ по-таблично, от таблицы с номером 0, внутри таблицы правила идут в порядке приоритетов, от большего к меньшему