OpenStack Neutron Floating Ip: различия между версиями
Sirmax (обсуждение | вклад) |
Sirmax (обсуждение | вклад) |
||
(не показано 13 промежуточных версий этого же участника) | |||
Строка 3: | Строка 3: | ||
[[Категория:Linux]] |
[[Категория:Linux]] |
||
[[Категория:Networking]] |
[[Категория:Networking]] |
||
− | [[Категория: |
+ | [[Категория:Iptables]] |
+ | [[Категория:OpenFlow]] |
||
+ | [[Категория:VxLAN]] |
||
=TODO= |
=TODO= |
||
Строка 2655: | Строка 2657: | ||
</PRE> |
</PRE> |
||
Далее трафик выходит из недр OpenVSWitch и попадает в tap интерфейс <code>tap7eed9c11-3d</code> |
Далее трафик выходит из недр OpenVSWitch и попадает в tap интерфейс <code>tap7eed9c11-3d</code> |
||
+ | |||
+ | ==Трафик на Compute Node за пределами OpenVSwitch== |
||
+ | После того как трафик покинул OpenVSwitch его можно наблюдать на интерфейсе: <BR> |
||
+ | <code> |
||
+ | ip -d link show dev tap7eed9c11-3d |
||
+ | </code> |
||
+ | <PRE> |
||
+ | 53: tap7eed9c11-3d: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1430 qdisc fq_codel master ovs-system state UNKNOWN mode DEFAULT group default qlen 1000 |
||
+ | link/ether fe:16:3e:ea:49:b7 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65521 |
||
+ | tun type tap pi off vnet_hdr on persist off |
||
+ | openvswitch_slave addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 |
||
+ | </PRE> |
||
+ | |||
+ | Далее остался один шаг - связать виртуальную машину и интрерфейс <code>tap</code> |
||
+ | |||
+ | {{Note|"TUN/TAP в 2 словах": |
||
+ | Пакет, посылаемый операционной системой через TUN/TAP устройство обрабатывается программой, которая контролирует это устройство. <BR> |
||
+ | Получение данных происходит через специальный файловый дескриптор, таким образом программа просто считывает данные с файлового дескриптора. <BR> |
||
+ | Сама программа также может отправлять пакеты через TUN/TAP устройство выполняя запись в тот же файловый дескриптор. <BR> |
||
+ | В таком случае TUN/TAP устройство доставляет (или «внедряет») такой пакет в сетевой стек операционной системы, эмулируя тем самым доставку пакета с внешнего устройства.<BR> |
||
+ | }} |
||
+ | |||
+ | Я не нашел простого способа (пока?) понять какой процесс использует интерфейс зная только имя интерфейса. |
||
+ | <BR> |
||
+ | По тому пока-что я вижу только один вариант - пройти по конфигурации машин в цикле и найти нужный инстанс (криво это конечно) |
||
+ | |||
+ | <PRE> |
||
+ | virsh dumpxml instance-000000b2 | grep 'tap7eed9c11-3d' |
||
+ | <target dev='tap7eed9c11-3d'/> |
||
+ | </PRE> |
||
+ | |||
+ | =Helpers= |
||
+ | Всякие короткие скрипты которые упрощают жизнь |
||
+ | ==Traffic Diff== |
||
+ | |||
+ | Небольшой скриптик, предназначеный для того что бы видеть по каким OpenFlow правилам изменились счетчики байт,<BR> |
||
+ | что полезно что бы быстро понять какое именно правило срабатывает |
||
+ | {{#spoiler:show=ovs_show_traffic_diff.sh| |
||
+ | |||
+ | <PRE> |
||
+ | #!/bin/bash |
||
+ | |||
+ | |||
+ | SLEEP=2 |
||
+ | |||
+ | #set -eu${DEBUG:+x} |
||
+ | show_help_and_exit() { |
||
+ | echo "" |
||
+ | echo "This script is show difference between 2 probes of dump-flows," |
||
+ | echo "in order to find active rules which matches traffic right now" |
||
+ | echo "" |
||
+ | echo "Usage example:" |
||
+ | echo "./ovs_show_traffic_diff.sh --bridge=br-int --table-number=20" |
||
+ | echo "" |
||
+ | echo " --bridge : OpenVSwitch bridge, can be found with ovs-vsctl show command" |
||
+ | echo " --table-number : Number of OpenFlow table, all tables can be found with command ovs-ofctl dump-flows <BRIDGE-NAME> " |
||
+ | echo "" |
||
+ | |||
+ | exit 0 |
||
+ | } |
||
+ | |||
+ | check_mandatory_parameters() { |
||
+ | if [ -z "${TABLE_NUMBER}" ]; |
||
+ | then |
||
+ | echo "Please define --table-number=<number of OpenFlow table for bridge>" |
||
+ | show_help_and_exit |
||
+ | fi |
||
+ | |||
+ | if [ -z "${BRIDGE}" ]; |
||
+ | then |
||
+ | echo "Please define --brifge=<bridge-name>" |
||
+ | show_help_and_exit |
||
+ | fi |
||
+ | } |
||
+ | |||
+ | |||
+ | |||
+ | TEMP=$(getopt -n "$0" -a -l "bridge:,table-number:,help" -- -- "$@") |
||
+ | #echo ${TEMP} |
||
+ | |||
+ | [ $? -eq 0 ] || exit |
||
+ | |||
+ | eval set -- "$TEMP" |
||
+ | |||
+ | while [ $# -gt 0 ]; |
||
+ | do |
||
+ | case "$1" in |
||
+ | --bridge) |
||
+ | BRIDGE="$2"; |
||
+ | shift |
||
+ | ;; |
||
+ | --table-number) |
||
+ | TABLE_NUMBER="$2"; |
||
+ | shift |
||
+ | ;; |
||
+ | --help) |
||
+ | help; |
||
+ | shift |
||
+ | ;; |
||
+ | --) |
||
+ | shift |
||
+ | ;; |
||
+ | esac |
||
+ | shift; |
||
+ | done |
||
+ | |||
+ | check_mandatory_parameters |
||
+ | |||
+ | echo "BRIDGE: ${BRIDGE}"; |
||
+ | echo "TABLE_NUMBER: $TABLE_NUMBER"; |
||
+ | |||
+ | set -eu${DEBUG:+x} |
||
+ | |||
+ | OVS_CONTAINER_ID=$(docker ps | grep '/tmp/openvswitch-vs' | awk '{ print $1 }') |
||
+ | |||
+ | echo ${OVS_CONTAINER_ID} |
||
+ | |||
+ | TMP_FIRST_PROBE=$(mktemp) |
||
+ | TMP_SECOND_PROBE=$(mktemp) |
||
+ | |||
+ | # This code do the following |
||
+ | # 1. dump flows |
||
+ | # 2. remove duration field, because duration always changes even if no new packets in rule |
||
+ | # 3. removes rules with no traffic (zero bytes) |
||
+ | # 4. saves result to the file |
||
+ | docker exec -ti ${OVS_CONTAINER_ID} ovs-ofctl dump-flows ${BRIDGE} | grep "table=${TABLE_NUMBER}, " | sed s/duration=.*s,/''/ | grep -v ' n_bytes=0, ' 2>&1 > ${TMP_FIRST_PROBE} |
||
+ | # 5. wait some time |
||
+ | sleep ${SLEEP} |
||
+ | # 6. repeat steps 1-4, but save to another file |
||
+ | docker exec -ti ${OVS_CONTAINER_ID} ovs-ofctl dump-flows ${BRIDGE} | grep "table=${TABLE_NUMBER}, " | sed s/duration=.*s,/''/ |grep -v ' n_bytes=0, ' 2>&1 > ${TMP_SECOND_PROBE} |
||
+ | # 7. compare results, ignore exit code |
||
+ | diff ${TMP_FIRST_PROBE} ${TMP_SECOND_PROBE} \ |
||
+ | || true |
||
+ | |||
+ | |||
+ | # Remove tmp files, TODO: make a trap |
||
+ | rm -f "${TMP_FIRST_PROBE}" |
||
+ | rm -f "${TMP_SECOND_PROBE}" |
||
+ | </PRE> |
||
+ | }} |
||
=Ссылки= |
=Ссылки= |
Текущая версия на 09:26, 8 октября 2024
TODO
Этот документ похоже слишком длинный, его не удобно писать, возможно разбить на более мелкие части (?)
TL;DR
Краткий список команд
Утилита ovs-tcpdump
не показывает трафик на виртуальных патчкордах, требуется исслдедовать почему и как настроить показ, но предположу что требуется настроить mirroring на какой-то порт с другим типом
Как трафик попадает из внешнего мира на 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.
В реальной жизни в окружении клиента доступа на роутеры и коммутаторы может не быть и тогда единственный способ понять через какую Control/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
Прохождение тарфика внутри Control/Network 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
Таблицы коммутатора br-tun
Для простоты просмотра вырежем из вывода счетчики и прочие поля которые не влияют на коммутацию пакета:
ovs-ofctl dump-flows br-tun | awk '{print $3" "$6" "$7}' | column -t
Вывод выглядит так (2 строки для примера)
table=0, priority=1,in_port="patch-int" actions=resubmit(,1) table=0, priority=1,in_port="vxlan-0a48080a" actions=resubmit(,4)
Для сравнения полный вывод без форматирования:
cookie=0x664e52e9b9d23ed7, duration=21138.026s, table=0, n_packets=105243, n_bytes=9417514, priority=1,in_port="patch-int" actions=resubmit(,1) cookie=0x664e52e9b9d23ed7, duration=21128.685s, table=0, n_packets=0, n_bytes=0, priority=1,in_port="vxlan-0a48080a" actions=resubmit(,4)
Поля,которые не интересуют для анализа прохождения пакета и вырезаны:
- cookie
- duration
- n_packets
- n_bytes
Далее проджолжаем анализ по-таблично, от таблицы с номером 0, внутри таблицы правила идут в порядке приоритетов, от большего к меньшему
Пакет попадает в коммутатор через порт patch-int
, и имеет мак назначения fa:16:3e:ea:49:b7
table 0
коммутатора br-tun
table=0, priority=1,in_port="patch-int" actions=resubmit(,1) table=0, priority=1,in_port="vxlan-0a48080a" actions=resubmit(,4) table=0, priority=1,in_port="vxlan-0a48080d" actions=resubmit(,4) table=0, priority=1,in_port="vxlan-0a480809" actions=resubmit(,4) table=0, priority=0 actions=drop
Тут видно, что пакеты с порта patch-int
передаются в таблицу 1 (проверка по входящему порту)
table 1
коммутатора br-tun
table=1, priority=0 actions=resubmit(,2)
Безусловный переход в таблицу 2 (зачем ?)
table 2
коммутатора br-tun
table=2, priority=1,arp,dl_dst=ff:ff:ff:ff:ff:ff actions=resubmit(,21) table=2, priority=0,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,20) table=2, priority=0,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,22)
Это правила в переводе на "язык человеков" означают:
- unicast ethernet адреса получения передаем в таблицу 20
- multicast ethernet адреса получения передаем в таблицу 22
Если описать более "стого" то читать так (для обоих правил):
- взять мак-адрес получателя, надожить на него маску (01:00:00:00:00:00) (в обоих правилах маска одинаковая)
- в результате работы может получиться 2 возможных значения (два значения, по тому что если перевести маску в двоичный вид то в полученном числе есть 1 только в одном разряде, и при поразрядном умножении в результате будет тоже не боле одной единицы (но может быть и ноль единиц, так как в исходном маке в этом разряде уже был ноль)
- результат наложения маски даст знание 0 или 1 в младшем бите второго байта мак - адреса (например в маке который рассматриваем старший байт это fa:16:3e:ea:49:b7 (0xa) == 1010, который после наложения маски 0x1 (двоичное 0001 ) будет иместь значение 0000, так как младьший бит уже имел значение 0
В результате исследуемый пакет будет направлен в таблицу 20
table 20
коммутатора br-tun
table=20, priority=2,dl_vlan=1,dl_dst=fa:16:3e:55:eb:a8 actions=strip_vlan,load:0x24->NXM_NX_TUN_ID[],output:"vxlan-0a48080a" table=20, priority=2,dl_vlan=1,dl_dst=fa:16:3e:2b:3e:99 actions=strip_vlan,load:0x24->NXM_NX_TUN_ID[],output:"vxlan-0a480809" table=20, priority=2,dl_vlan=1,dl_dst=fa:16:3e:42:68:31 actions=strip_vlan,load:0x24->NXM_NX_TUN_ID[],output:"vxlan-0a480809" table=20, priority=2,dl_vlan=1,dl_dst=fa:16:3e:ea:49:b7 actions=strip_vlan,load:0x24->NXM_NX_TUN_ID[],output:"vxlan-0a48080d" table=20, hard_timeout=300, priority=1,vlan_tci=0x0001/0x0fff,dl_dst=fa:16:3e:ea:49:b7 table=20, priority=0 actions=resubmit(,22)
В этой таблице есть совпадения по маку получателя - отработает правило
table=20, priority=2,dl_vlan=1,dl_dst=fa:16:3e:ea:49:b7 actions=strip_vlan,load:0x24->NXM_NX_TUN_ID[],output:"vxlan-0a48080d"
Это правило:
strip_vlan
снимет все VLAN тегиload:0x24->NXM_NX_TUN_ID[]
это дествие определяет VNI - аналог VlanID для VXLAN, 0x24 == 36 (десятичное)output:"vxlan-0a48080d"
отправит пакет в портvxlan-0a48080d
порт vxlan-0a48080d
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.11", out_key=flow, remote_ip="10.72.8.13"}
Пакет будет инкапсулирован в VxLAN и отправлен на адрес remote_ip="10.72.8.13"
(адрес отправителя будет local_ip="10.72.8.11"
)
Проверка tcpdump
Так как пакет на данном этапе покинет Network/Controller node, то можно попробовать увидеть его tcpdump
Проверить через какой интерфейс будет отправле пакет для remote_ip="10.72.8.13"
можно командой:
ip ro get 10.72.8.13
10.72.8.13 dev tenant src 10.72.8.11 uid 0 cache
Искомый интерфейс имеет имя tenant
Проверив трафик tcpdump можно видеть что VXLAN трафик с VNI=36 (0x24) передается:
tcpdump -n -i tenant -ee tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on tenant, link-type EN10MB (Ethernet), capture size 262144 bytes 08:52:12.889945 52:54:15:ac:ac:15 > 5e:24:8c:10:3d:20, ethertype IPv4 (0x0800), length 148: 10.72.8.11.36100 > 10.72.8.13.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol 08:52:12.890454 5e:24:8c:10:3d:20 > 52:54:15:ac:ac:15, ethertype IPv4 (0x0800), length 148: 10.72.8.13.38067 > 10.72.8.11.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol 08:52:12.990619 52:54:15:ac:ac:15 > 5e:24:8c:10:3d:20, ethertype IPv4 (0x0800), length 148: 10.72.8.11.36100 > 10.72.8.13.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol 08:52:12.991146 5e:24:8c:10:3d:20 > 52:54:15:ac:ac:15, ethertype IPv4 (0x0800), length 148: 10.72.8.13.38067 > 10.72.8.11.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol
Далее обработка на стороне Network/Control Node заканчивается, и дальнейшая счастливая жизнь пакета продолжается на Compute Node
Судя по всему tcpdump не знает что внутри так как не знает что делать со згначением "Next Protocol":
https://github.com/the-tcpdump-group/tcpdump/blob/master/print-vxlan-gpe.c
Compute Node
Compute node имеет адрес 10.72.8.13
, однако это не означает что это маршрутизируемый адрес - вполне возможно что это адрес используется только для построения оверлейной сети. (как раз наш случай)
Выяснить адрес для подключения - обратится к документации по клауду, это полностью зависит от того как был развернут конкретный клауд и общих рекомендаций тут нет.
Проверить что трафик доходит до Compute Node можно tcpdump
сначала убедиться что адрес присутствует на ноде:
tenant: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 10.72.8.13 netmask 255.255.255.0 broadcast 10.72.8.255 inet6 fe80::5c24:8cff:fe10:3d20 prefixlen 64 scopeid 0x20<link> ether 5e:24:8c:10:3d:20 txqueuelen 1000 (Ethernet) RX packets 878696 bytes 93808692 (93.8 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 616662 bytes 90313355 (90.3 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Проверить что видно трафик VXLAN с VNI=36 (0x24)
tcpdump -n -i tenant -ee
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on tenant, link-type EN10MB (Ethernet), capture size 262144 bytes 09:19:04.142325 52:54:15:ac:ac:15 > 5e:24:8c:10:3d:20, ethertype IPv4 (0x0800), length 148: 10.72.8.11.36100 > 10.72.8.13.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol 09:19:04.142706 5e:24:8c:10:3d:20 > 52:54:15:ac:ac:15, ethertype IPv4 (0x0800), length 148: 10.72.8.13.38067 > 10.72.8.11.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol 09:19:05.145801 52:54:15:ac:ac:15 > 5e:24:8c:10:3d:20, ethertype IPv4 (0x0800), length 148: 10.72.8.11.36100 > 10.72.8.13.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol 09:19:05.146111 5e:24:8c:10:3d:20 > 52:54:15:ac:ac:15, ethertype IPv4 (0x0800), length 148: 10.72.8.13.38067 > 10.72.8.11.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol ^C 4 packets captured 4 packets received by filter 0 packets dropped by kernel
Прохождение трафика внутри OpenVSwitch (Compute Node)
В процессе написания этого документа у меня была необходимость обновить OpenStack что повлекло за собой перезагрузку нод, и виртуальный роутер переместился на другую Network/Control ноду.
Соответственно сменился адрес с которого идет рафик - вместо 10.72.8.11
(как в дампе выше) стал 10.72.8.9
tcpdump -n -i tenant -ee tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on tenant, link-type EN10MB (Ethernet), capture size 262144 bytes 13:58:15.889411 52:54:15:ab:ab:15 > 5e:24:8c:10:3d:20, ethertype IPv4 (0x0800), length 148: 10.72.8.9.55052 > 10.72.8.13.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol 13:58:15.890550 5e:24:8c:10:3d:20 > 52:54:15:ab:ab:15, ethertype IPv4 (0x0800), length 148: 10.72.8.13.36859 > 10.72.8.9.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol 13:58:16.886610 52:54:15:ab:ab:15 > 5e:24:8c:10:3d:20, ethertype IPv4 (0x0800), length 148: 10.72.8.9.55052 > 10.72.8.13.4790: VXLAN-GPE, flags [I], vni 36: ERROR: unknown-next-protocol
Определить прт можно по ip адресу - в этом случае это remote_ip="10.72.8.9"
ovs-vsctl show
Port vxlan-0a480809 Interface vxlan-0a480809 type: vxlan options: {df_default="true", dst_port="4790", egress_pkt_mark="0", in_key=flow, local_ip="10.72.8.13", out_key=flow, remote_ip="10.72.8.9"}
Полный вывод команды скрыт под спойлер:
В результате видно что трафик попадает в порт
vxlan-0a480809
коммутатора br-tun
Дополнительно можно убедиться в этом с помощью команды ovs-tcpdump
:
ovs-tcpdump -i vxlan-0a480809
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ovsmi645790, link-type EN10MB (Ethernet), capture size 262144 bytes 14:06:40.097042 IP6 :: > ff02::1:fff1:28c1: ICMP6, neighbor solicitation, who has fe80::4c43:b8ff:fef1:28c1, length 32 14:06:40.338960 IP 192.168.22.253 > 10.255.4.184: ICMP echo request, id 8336, seq 503, length 64 14:06:40.339240 IP 10.255.4.184 > 192.168.22.253: ICMP echo reply, id 8336, seq 503, length 64 14:06:40.649072 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28 14:06:41.129165 IP6 fe80::4c43:b8ff:fef1:28c1 > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28 14:06:41.129181 IP6 fe80::4c43:b8ff:fef1:28c1 > ip6-allrouters: ICMP6, router solicitation, length 16 14:06:41.345654 IP 192.168.22.253 > 10.255.4.184: ICMP echo request, id 8336, seq 504, length 64 14:06:41.346027 IP 10.255.4.184 > 192.168.22.253: ICMP echo reply, id 8336, seq 504, length 64 14:06:42.025131 IP6 fe80::4c43:b8ff:fef1:28c1 > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28 14:06:42.344460 IP 192.168.22.253 > 10.255.4.184: ICMP echo request, id 8336, seq 505, length 64 14:06:42.344682 IP 10.255.4.184 > 192.168.22.253: ICMP echo reply, id 8336, seq 505, length 64
( адрес 192.168.22.253 это адрес откуда идет пинг на ВМ )
если добавить ключ -ee
то можно было бы увидеть заголовки VLAN но в данном случае их нет.
Прохождение трафика через виртуальный коммутатор br-tun
(Compute Node)
Так же как и для других OpenFlow-коммутаторов, требуется изучить таблицу правил что бы понять как будет идти трафик:
ovs-ofctl dump-flows br-tun
Полный вывод скрыт, дальше анализируем используя только значимые поля.
table 0
коммутатора br-tun
(Compute Node)
table=0, priority=1,in_port="patch-int" actions=resubmit(,1) table=0, priority=1,in_port="vxlan-0a48080a" actions=resubmit(,4) table=0, priority=1,in_port="vxlan-0a48080b" actions=resubmit(,4) table=0, priority=1,in_port="vxlan-0a480809" actions=resubmit(,4) table=0, priority=0 actions=drop
Тут видно, что все пакеты с VxLAN-интерфейсов передаются в таблицу 4 (actions=resubmit(,4)
)
table 4
коммутатора br-tun
(Compute Node)
table=4, priority=1,tun_id=0x24 actions=mod_vlan_vid:1,resubmit(,9) table=4, priority=0 actions=drop
Тут видно что все пакеты с tun_id=0x24
, которым соответствует и анализируемый трафик (0x24 = 36, и VNI=36 если смотреть в tcpdump выше)
передаются далее в таблицу 9, (resubmit(,9)
)
после того как на них будет установлен VLAN ID=1 (mod_vlan_vid:1
)
table 9
коммутатора br-tun
(Compute Node)
table=9, priority=1,dl_src=fa:16:3f:0e:d7:45 actions=output:"patch-int" table=9, priority=1,dl_src=fa:16:3f:38:c0:62 actions=output:"patch-int" table=9, priority=1,dl_src=fa:16:3f:64:4e:1f actions=output:"patch-int" table=9, priority=1,dl_src=fa:16:3f:96:cd:a5 actions=output:"patch-int" table=9, priority=1,dl_src=fa:16:3f:a0:1e:1b actions=output:"patch-int" table=9, priority=1,dl_src=fa:16:3f:e0:b7:4b actions=output:"patch-int" table=9, priority=0 actions=resubmit(,10)
Напомню, что как было выяснено выше, пакет имет мак-адрес получателяfa:16:3e:ea:49:b7
, а мак-адрес отправителя - fa:16:3e:69:cd:07
Мак-адрес отправителя - это мак-адрес интерфейса виртуального роутера
ни одно из правил, кроме последнего не срабатывает - и пакет передается в таблицу 10
table 10
коммутатора br-tun
(Compute Node)
table=10, priority=1 actions=learn(table=20,hard_timeout=300,priority=1,cookie=0xca3e4b7bf6ec3ebf,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:0->NXM_OF_VLAN_TCI[],load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],output:OXM_OF_IN_PORT[]),output:"patch-int"
Достаточно запутанное правило, однако из него видно что кроме всего прочего пакет покидает коммутатор через порт patch-int.
- learn(
table=20
hard_timeout=300
priority=1
NXM_OF_VLAN_TCI[0..11]
NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]
load:0->NXM_OF_VLAN_TCI[]
load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[]
output:OXM_OF_IN_PORT[])
output:"patch-int"
Тут происходит 2 действия
- пакет отправляется через порт
patch-int
- создается правило в табличке 20
Пример правила из таблицы 20
table=20, priority=2,dl_vlan=1,dl_dst=fa:16:3e:69:cd:07 actions=strip_vlan,load:0x24->NXM_NX_TUN_ID[],output:"vxlan-0a480809"
Некоторые части более-менее понятны, и в целом назначение этого действия - создать правило для обратного трафика
NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]
означает что в match-части правилаdl_dst
будет совпадать с маком отправителя (fa:16:3e:69:cd:07)output:OXM_OF_IN_PORT[])
- выставит OUT порт таки как был IN порт пакетаload:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[]
- cохранить TUN_ID
Но по некоторым частям ясности нет (приоритет 2 а не 1, load:0->NXM_OF_VLAN_TCI[]
)
Проверить к какому виртуальному коммутатору принадлежит порт можно командой ovs-vsctl show
Порт patch-int
это порт типа патч-корд, второй конец которого это порт patch-tun
(что видно из options: {peer=patch-tun}
)
Port patch-int Interface patch-int type: patch options: {peer=patch-tun}
Порт patch-tun}
:
Port patch-tun Interface patch-tun type: patch options: {peer=patch-int}
Этот порт принадлежит коммутатору br-int
, и далее трафик идет в него.
Прохождение трафика через виртуальный коммутатор br-int
(Compute Node)
Коммутатор br-int
Bridge br-int Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure datapath_type: system Port int-br-ch-os-fl Interface int-br-ch-os-fl type: patch options: {peer=phy-br-ch-os-fl} Port br-int Interface br-int type: internal Port patch-tun Interface patch-tun type: patch options: {peer=patch-int} Port tap7eed9c11-3d tag: 1 Interface tap7eed9c11-3d
Так же как и для других OpenFlow-коммутаторов, требуется изучить таблицу правил что бы понять как будет идти трафик:
ovs-ofctl dump-flows br-int
Полный вывод скрыт, дальше анализируем используя только значимые поля.
table 0
коммутатора br-int
(Compute Node)
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:f9:d4:00 actions=resubmit(,4) table=0, priority=5,in_port="patch-tun",dl_dst=fa:16:3f:f9:d4:00 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:e0:b7:4b 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:e0:b7:4b actions=resubmit(,1) table=0, priority=2,in_port="int-br-ch-os-fl" actions=drop table=0, priority=0 actions=resubmit(,60)
Напомню, что анализируемый трафик:
in_port=patch-tun
(интерфейс через который трафик попал в коммтатор)dl_dst=fa:16:3e:ea:49:b7
(мак-адрес получателя)dl_src=fa:16:3e:69:cd:07
(мак-адрес отправителя)
Тут видно, что
- правило с приоритеом 200 выставляет значение reg3=1 для тех пакетов у которых reg3=0
- правила с приоритетом 5 не совпадают (не тот мак адрес или не тот порт и не тот мак-адрес)
- правила с приоритетом 4 - не совпадает порт
- правила с приоритетом 2 - не совпадает мак-адрес отправителя или интерфейс
Итого, отрабатывает только последнее правило с приоритетом 0 и дальше пакет будет отработан в таблице 60
table 60
коммутатора br-int
(Compute Node)
table=60, priority=100,in_port="tap7eed9c11-3d" actions=load:0x3->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],resubmit(,71) table=60, priority=90,dl_vlan=1,dl_dst=fa:16:3e:ea:49:b7 actions=load:0x3->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],strip_vlan,resubmit(,81) table=60, priority=3 actions=NORMAL
Тут срабатывает правило
table=60, priority=90,dl_vlan=1,dl_dst=fa:16:3e:ea:49:b7 actions=load:0x3->NXM_NX_REG5[],load:0x1->NXM_NX_REG6[],strip_vlan,resubmit(,81)
Далее пакет попадает в таблицу 81
table 81
коммутатора br-int
(Compute Node)
table=81, priority=100,arp,reg5=0x3 actions=output:"tap7eed9c11-3d" table=81, priority=100,icmp6,reg5=0x3,icmp_type=130 actions=output:"tap7eed9c11-3d" table=81, priority=100,icmp6,reg5=0x3,icmp_type=135 actions=output:"tap7eed9c11-3d" table=81, priority=100,icmp6,reg5=0x3,icmp_type=136 actions=output:"tap7eed9c11-3d" table=81, priority=95,udp,reg5=0x3,tp_src=67,tp_dst=68 actions=output:"tap7eed9c11-3d" table=81, priority=95,udp6,reg5=0x3,tp_src=547,tp_dst=546 actions=output:"tap7eed9c11-3d" table=81, priority=90,ct_state=-trk,ip,reg5=0x3 actions=ct(table=82,zone=NXM_NX_REG6[0..15]) table=81, priority=90,ct_state=-trk,ipv6,reg5=0x3 actions=ct(table=82,zone=NXM_NX_REG6[0..15]) table=81, priority=80,ct_state=+trk,reg5=0x3 actions=resubmit(,82) table=81, priority=0 actions=drop
Далее начинается какой то ад, и это правило я уже не могу разобрать
table=81, priority=90,ct_state=-trk,ip,reg5=0x3 actions=ct(table=82,zone=NXM_NX_REG6[0..15])
и трафик попадает в таблицу 82
table 82
коммутатора br-int
(Compute Node)
table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x4000/0xc000 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x8000/0xc000 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x4000/0xc000 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x8000/0xc000 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x2000/0xe000 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xc000/0xe000 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x2000/0xe000 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xc000/0xe000 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x1000/0xf000 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xe000/0xf000 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x1000/0xf000 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xe000/0xf000 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x800/0xf800 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xf000/0xf800 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x800/0xf800 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xf000/0xf800 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x400/0xfc00 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xf800/0xfc00 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x400/0xfc00 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xf800/0xfc00 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x200/0xfe00 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xfc00/0xfe00 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x200/0xfe00 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xfc00/0xfe00 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x100/0xff00 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xfe00/0xff00 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x100/0xff00 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xfe00/0xff00 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x80/0xff80 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xff00/0xff80 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x80/0xff80 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xff00/0xff80 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x40/0xffc0 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xff80/0xffc0 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x40/0xffc0 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xff80/0xffc0 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x20/0xffe0 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xffc0/0xffe0 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x20/0xffe0 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xffc0/0xffe0 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x10/0xfff0 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xffe0/0xfff0 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x10/0xfff0 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xffe0/0xfff0 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x8/0xfff8 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xfff0/0xfff8 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x8/0xfff8 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xfff0/0xfff8 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x4/0xfffc actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xfff8/0xfffc actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x4/0xfffc actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xfff8/0xfffc actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x2/0xfffe actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0xfffc/0xfffe actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0x2/0xfffe actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=0xfffc/0xfffe actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=1 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=65534 actions=output:"tap7eed9c11-3d" table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=1 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=77,ct_state=+new-est,tcp,reg5=0x3,tp_dst=65534 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=75,ct_state=+est-rel-rpl,icmp,reg5=0x3 actions=output:"tap7eed9c11-3d" table=82, priority=75,ct_state=+new-est,icmp,reg5=0x3 actions=ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=70,ct_state=+est-rel-rpl,ip,reg5=0x3 actions=conjunction(16,2/2) table=82, priority=70,ct_state=+est-rel-rpl,ipv6,reg5=0x3 actions=conjunction(24,2/2) table=82, priority=70,ct_state=+new-est,ip,reg5=0x3 actions=conjunction(17,2/2) table=82, priority=70,ct_state=+new-est,ipv6,reg5=0x3 actions=conjunction(25,2/2) table=82, priority=70,conj_id=16,ct_state=+est-rel-rpl,ip,reg5=0x3 actions=load:0x10->NXM_NX_REG7[],output:"tap7eed9c11-3d" table=82, priority=70,conj_id=24,ct_state=+est-rel-rpl,ipv6,reg5=0x3 actions=load:0x18->NXM_NX_REG7[],output:"tap7eed9c11-3d" table=82, priority=70,conj_id=17,ct_state=+new-est,ip,reg5=0x3 actions=load:0x11->NXM_NX_REG7[],ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=70,conj_id=25,ct_state=+new-est,ipv6,reg5=0x3 actions=load:0x19->NXM_NX_REG7[],ct(commit,zone=NXM_NX_REG6[0..15]),output:"tap7eed9c11-3d",resubmit(,92) table=82, priority=70,ct_state=+est-rel-rpl,ip,reg6=0x1,nw_src=10.255.4.184 actions=conjunction(16,1/2) table=82, priority=70,ct_state=+new-est,ip,reg6=0x1,nw_src=10.255.4.184 actions=conjunction(17,1/2) table=82, priority=50,ct_state=+inv+trk actions=resubmit(,93) table=82, priority=50,ct_mark=0x1,reg5=0x3 actions=resubmit(,93) table=82, priority=50,ct_state=+est-rel+rpl,ct_zone=1,ct_mark=0,reg5=0x3 actions=output:"tap7eed9c11-3d" table=82, priority=50,ct_state=-new-est+rel-inv,ct_zone=1,ct_mark=0,reg5=0x3 actions=output:"tap7eed9c11-3d" table=82, priority=40,ct_state=-est,reg5=0x3 actions=resubmit(,93) table=82, priority=40,ct_state=+est,ip,reg5=0x3 actions=ct(commit,zone=NXM_NX_REG6[0..15],exec(load:0x1->NXM_NX_CT_MARK[])) table=82, priority=40,ct_state=+est,ipv6,reg5=0x3 actions=ct(commit,zone=NXM_NX_REG6[0..15],exec(load:0x1->NXM_NX_CT_MARK[])) table=82, priority=0 actions=drop
Тут сложно, а у меня лапки, и я не могу прочитать эти правила
Тут пришлось срезать угол и воспользоваться знанием того что есть только одна ВМка с активным трафиком - и то правило где меняются значение счетчиков и будет искомым:
cookie=0xc8775018ea65cafd, table=82, n_packets=4552, n_bytes=313378, priority=77,ct_state=+est-rel-rpl,tcp,reg5=0x3,tp_dst=0x10/0xfff0 actions=output:"tap7eed9c11-3d"
Далее трафик выходит из недр OpenVSWitch и попадает в tap интерфейс tap7eed9c11-3d
Трафик на Compute Node за пределами OpenVSwitch
После того как трафик покинул OpenVSwitch его можно наблюдать на интерфейсе:
ip -d link show dev tap7eed9c11-3d
53: tap7eed9c11-3d: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1430 qdisc fq_codel master ovs-system state UNKNOWN mode DEFAULT group default qlen 1000 link/ether fe:16:3e:ea:49:b7 brd ff:ff:ff:ff:ff:ff promiscuity 1 minmtu 68 maxmtu 65521 tun type tap pi off vnet_hdr on persist off openvswitch_slave addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
Далее остался один шаг - связать виртуальную машину и интрерфейс tap
Пакет, посылаемый операционной системой через TUN/TAP устройство обрабатывается программой, которая контролирует это устройство.
Получение данных происходит через специальный файловый дескриптор, таким образом программа просто считывает данные с файлового дескриптора.
Сама программа также может отправлять пакеты через TUN/TAP устройство выполняя запись в тот же файловый дескриптор.
В таком случае TUN/TAP устройство доставляет (или «внедряет») такой пакет в сетевой стек операционной системы, эмулируя тем самым доставку пакета с внешнего устройства.
Я не нашел простого способа (пока?) понять какой процесс использует интерфейс зная только имя интерфейса.
По тому пока-что я вижу только один вариант - пройти по конфигурации машин в цикле и найти нужный инстанс (криво это конечно)
virsh dumpxml instance-000000b2 | grep 'tap7eed9c11-3d' <target dev='tap7eed9c11-3d'/>
Helpers
Всякие короткие скрипты которые упрощают жизнь
Traffic Diff
Небольшой скриптик, предназначеный для того что бы видеть по каким OpenFlow правилам изменились счетчики байт,
что полезно что бы быстро понять какое именно правило срабатывает