Открытый vSwitch и преобразование портов

у нас есть очень конкретное требование, которое я хочу решить с помощью Open vSwitch. Это уже как-то работает - вы можете показать мне, что мне здесь не хватает?

Требование: контейнер Docker, подключенный к интерфейсу mac-vlan, предоставляет службы на определенном порту (необходимо транслировать в локальной сети). Нам нужно, чтобы службы были доступны на другом порту - и нет никакого способа настроить порт, на котором запущена служба. Мы уже пробовали разные подходы (обратный прокси, директивы docker --ports и т. Д.), Которые не работали по разным причинам, в основном потому, что нам все еще нужно придерживаться IP-адреса интерфейса mac-vlan.

Эта базовая настройка довольно исправна, моя основная цель - заставить ее работать таким образом, я думаю, что это должно быть возможно.

Среда: Arch Linux с ядром core / linux 5.10.9 и пакетами community / openvswitch 2.14.1-1 , community / docker 1: 20.10 .2-4

Enter Open vSwitch: мы создали интерфейс mac-vlan на мосту OVS и хотим использовать директивы OpenFlow для изменения порта.

# ovs-vsctl show
... output omitted
    Bridge br1
        Port br1.200
            tag: 200
            Interface br1.200      <<< our container is connected here
                type: internal
        Port br1
            Interface br1
                type: internal
        Port patch-br0
            Interface patch-br0    <<< uplink to OVS bridge with physical interface
                type: patch
                options: {peer=patch-br1}

Использование Nginx для демонстрации должно работать с любым контейнером ...

# docker network create -d macvlan --subnet=172.16.0.0/20 --ip-range=172.16.13.0/29 --gateway=172.16.0.1 -o parent=br1.200 mv.200
# docker run -d --name web --network mv.200 nginx

Пока все ясно, curl http://172.16.13.0 (который в данном случае является веб-контейнером) возвращает ' Добро пожаловать в Nginx!' страница по умолчанию.Теперь мы пробуем следующие конфигурации OpenFlow, чтобы сделать службу контейнера доступной через порт 9080.

Вариант 1:

# ovs-ofctl dump-flows br1
 cookie=0x0, duration=1647.225s, table=0, n_packets=16, n_bytes=1435, priority=50,ct_state=-trk,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=ct(table=0)
 cookie=0x0, duration=1647.223s, table=0, n_packets=3, n_bytes=234, priority=50,ct_state=+new+trk,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=ct(commit,nat(dst=172.16.13.0:80)),NORMAL
 cookie=0x0, duration=1647.221s, table=0, n_packets=11, n_bytes=956, priority=50,ct_state=+est+trk,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=ct(nat),NORMAL
 cookie=0x0, duration=1647.219s, table=0, n_packets=0, n_bytes=0, priority=50,ct_state=-trk,tcp,nw_src=172.16.13.0,tp_src=80 actions=ct(table=0)
 cookie=0x0, duration=1647.217s, table=0, n_packets=12, n_bytes=2514, priority=50,ct_state=+trk,tcp,nw_src=172.16.13.0,tp_src=80 actions=ct(nat),NORMAL
 cookie=0x0, duration=84061.461s, table=0, n_packets=309364, n_bytes=36251324, priority=0 actions=NORMAL

Вариант результата 1:

Теперь curl http://172.16.13.0:9080 работает только в том случае, если уже есть активный поток, но он прерывается при первой попытке ( tcpdump -i br1.200 на сервере).

Client > Server : 172.16.1.51:46056 > 172.16.13.0:80 SYN
Server > Client : 172.16.13.0:80 > 172.16.1.51:46056 SYN ACK
Client > Server : 172.16.1.51:46056 > 172.16.13.0:9080 ACK      (destination port not translated)
Server > Client : 172.16.13.0:9080 > 172.16.1.51:46056 RST      (unknown to server)
Server > Client : 172.16.13.0:80 > 172.16.1.51:46056 SYN ACK
Client > Server : 172.16.1.51:46056 > 172.16.13.0:80 RST        (already ACK'ed)

Client > Server : 172.16.1.51:46058 > 172.16.13.0:80 SYN        (second curl)
Server > Client : 172.16.13.0:80 > 172.16.1.51:46058 SYN ACK
Client > Server : 172.16.1.51:46058 > 172.16.13.0:80 ACK        (now with correct port 80)
... (normal TCP connection from here)

Пакет №3 должен быть охвачен потоком №3, очевидно, он работает не так, как я думал.

# ovs-appctl dpctl/dump-conntrack | grep 172.16.13.0
tcp,orig=(src=172.16.1.51,dst=172.16.13.0,sport=46056,dport=9080),reply=(src=172.16.13.0,dst=172.16.1.51,sport=80,dport=46056),protoinfo=(state=CLOSING)
tcp,orig=(src=172.16.1.51,dst=172.16.13.0,sport=46058,dport=9080),reply=(src=172.16.13.0,dst=172.16.1.51,sport=80,dport=46058),protoinfo=(state=TIME_WAIT)

Можете ли вы помочь мне понять, почему действие ct (nat) для потока + trk + est не работает для первого соединения (но затем для второго)?

Вариант 2: (добавить mod_tp_dst к потоку №2)

# ovs-ofctl dump-flows br1
 cookie=0x0, duration=6182.935s, table=0, n_packets=0, n_bytes=0, priority=50,ct_state=-trk,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=ct(table=0)
 cookie=0x0, duration=6182.931s, table=0, n_packets=0, n_bytes=0, priority=50,ct_state=+new+trk,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=mod_tp_dst:80,ct(commit,nat(dst=172.16.13.0:80)),NORMAL
 cookie=0x0, duration=6182.928s, table=0, n_packets=0, n_bytes=0, priority=50,ct_state=+est+trk,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=ct(nat),NORMAL
 cookie=0x0, duration=6182.925s, table=0, n_packets=0, n_bytes=0, priority=50,ct_state=-trk,tcp,nw_src=172.16.13.0,tp_src=80 actions=ct(table=0)
 cookie=0x0, duration=6182.923s, table=0, n_packets=0, n_bytes=0, priority=50,ct_state=+trk,tcp,nw_src=172.16.13.0,tp_src=80 actions=ct(nat),NORMAL
 cookie=0x0, duration=81462.938s, table=0, n_packets=302990, n_bytes=35637543, priority=0 actions=NORMAL

Вариант результата 2:

Запуск curl http://172.16.13.0:9080 ситуация немного улучшается по сравнению с вариантом 1 ( tcpdump -i eth0 на клиенте).

Client > Server : 172.16.1.51:45974 > 172.16.13.0:9080 SYN
Server > Client : 172.16.13.0:80 > 172.16.1.51:45974 SYN ACK     (response source port not translated)
Client > Server : 172.16.1.51:45974 > 172.16.13.0:80 RST         (unknown to client)
Client > Server : 172.16.1.51:45974 > 172.16.13.0:9080 SYN       (retransmission)
Server > Client : 172.16.13.0:9080 > 172.16.1.51:45974 SYN ACK   (now with correct port 9080)
Client > Server : 172.16.1.51:45974 > 172.16.13.0:9080 ACK

Таким образом, соединение всегда работает, но также добавляется таймаут повторной передачи SYN к задержке установки сеанса.

# ovs-appctl dpctl/dump-conntrack | grep 172.16.13.0
tcp,orig=(src=172.16.1.51,dst=172.16.13.0,sport=45974,dport=80),reply=(src=172.16.13.0,dst=172.16.1.51,sport=80,dport=45974),protoinfo=(state=SYN_SENT)
tcp,orig=(src=172.16.1.51,dst=172.16.13.0,sport=45974,dport=9080),reply=(src=172.16.13.0,dst=172.16.1.51,sport=80,dport=1355),protoinfo=(state=TIME_WAIT)

Вы можете помочь мне понять, почему первый SYN ACK получен непереведенным? Flow # 5 и ct_state = + trk и actions = ct (nat) должны были покрыть это.

Спасибо, что прочитали этот длинный пост. Благодарю за любые подсказки!

0
задан 22 January 2021 в 13:29
1 ответ

Нашел способ заставить его работать, все еще не уверен, почему вариант 1 не работает...

Ключевым моментом здесь, похоже, является тот факт, что поток #3 в варианте 1 не был правильно подхвачен или conntrack не имел информации о NAT.

Вот дамп потоков, который работает у меня:

ovs-ofctl dump-flows br1
 cookie=0x0, duration=160.870s, table=0, n_packets=14, n_bytes=1156, priority=50,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=ct(table=1)
 cookie=0x0, duration=160.867s, table=0, n_packets=11, n_bytes=2430, priority=50,tcp,nw_src=172.16.13.0,tp_src=80 actions=ct(table=1)
 cookie=0x0, duration=184012.978s, table=0, n_packets=558802, n_bytes=60818179, priority=0 actions=NORMAL
 cookie=0x0, duration=160.865s, table=1, n_packets=2, n_bytes=156, priority=50,ct_state=+new,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=ct(commit,nat(dst=172.16.13.0:80)),NORMAL
 cookie=0x0, duration=160.862s, table=1, n_packets=12, n_bytes=1000, priority=50,tcp,nw_dst=172.16.13.0,tp_dst=9080 actions=mod_tp_dst:80,NORMAL
 cookie=0x0, duration=160.860s, table=1, n_packets=11, n_bytes=2430, priority=50,tcp,nw_src=172.16.13.0,tp_src=80 actions=ct(nat),NORMAL
0
ответ дан 24 April 2021 в 02:14

Теги

Похожие вопросы