OpenStack Neutron Floating Ip

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску


TODO

Этот документ похоже слишком длинный, его не удобно писать, возможно разбить на более мелкие части (?)

TL;DR

Краткий список команд


Note: "ovs-tcpdump":

Утилита 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

Note: "О роутерах в OpenStack":

Просмотреть роутеры можно командой 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
Note: "floating":

Изначально на этом интерфейсе присутствовал 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 коммутаторов)

Note: "OpenVswitch in Docker":

В этой инсталляции процессы 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 байт регистра 3
  • resubmit(,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

Note: "Почему Port Down?":

Можно было увидеть: 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


Note: "В поисках неймспейса":

На самом деле можно было предположить что это какой-то роутер 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

Note: "stdbuf": Без отключение буферизации например 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' (так она и назодится гуглом)
Netfilter-packet-flow.svg.png]

Из этой схемы становится более понятно в каком порядке какие таблицы просматривать.
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 только одно правило, пересылает пакеты в цепочку neutron-l3-agent-PREROUTING,
в которой нет ни одного правила, и как следствие к пакетам применяется правило по-умолчанию для
цепочки :PREROUTING - ACCEPT

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 в регистр 5
  • load:0x1->NXM_NX_REG6[] - записать значение 0x1 в регистр 6
  • resubmit(,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

Note: "ERROR: unknown-next-protocol":

Судя по всему 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)

Note: "Перезагрузка":

В процессе написания этого документа у меня была необходимость обновить 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

Note: "TUN/TAP в 2 словах":

Пакет, посылаемый операционной системой через TUN/TAP устройство обрабатывается программой, которая контролирует это устройство.
Получение данных происходит через специальный файловый дескриптор, таким образом программа просто считывает данные с файлового дескриптора.
Сама программа также может отправлять пакеты через TUN/TAP устройство выполняя запись в тот же файловый дескриптор.
В таком случае TUN/TAP устройство доставляет (или «внедряет») такой пакет в сетевой стек операционной системы, эмулируя тем самым доставку пакета с внешнего устройства.

Я не нашел простого способа (пока?) понять какой процесс использует интерфейс зная только имя интерфейса.
По тому пока-что я вижу только один вариант - пройти по конфигурации машин в цикле и найти нужный инстанс (криво это конечно)

virsh dumpxml instance-000000b2 | grep 'tap7eed9c11-3d'
      <target dev='tap7eed9c11-3d'/>

Helpers

Всякие короткие скрипты которые упрощают жизнь

Traffic Diff

Небольшой скриптик, предназначеный для того что бы видеть по каким OpenFlow правилам изменились счетчики байт,
что полезно что бы быстро понять какое именно правило срабатывает

Ссылки