Open vSwitch 和端口转换

Open vSwitch 和端口转换

我们有一个非常具体的需求,我想用 Open vSwitch 来解决。它已经以某种方式工作了 - 你能告诉我我这里缺少什么吗?

要求:连接到 mac-vlan 接口的 Docker 容器在特定端口上公开服务(需要在本地网络上广播)。我们需要在不同的端口上提供服务 - 并且无法配置运行服务的端口。我们已经尝试了不同的方法(反向代理、docker --ports 指令等),但由于各种原因,这些方法都没有奏效,主要是因为我们仍然必须坚持使用 mac-vlan 接口的 IP。

那个基础设置相当固定,我的主要目标是让它以这种方式工作,我认为这应该是可能的。

环境:Arch Linux 及其内核core/linux 5.10.9和软件包community/openvswitch 2.14.1-1community/docker 1:20.10.2-4

输入 Open vSwitch:我们在 OVS Bridge 上创建了 mac-vlan 接口,并想使用 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(在本例中为容器 Web)返回“欢迎使用 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)

您能否帮助我理解为什么 +trk+est 流的 ct(nat) 操作对第一个连接不起作用(但对第二个连接却起作用)?

变体 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:

与变体 1(在客户端)相比,运行curl http://172.16.13.0:9080情况略有改善。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 未经过转换就被接收吗?流程 #5 和 ct_state=+trk 以及 action=ct(nat) 应该已经涵盖了这一点。

感谢您阅读这篇长文。我非常感谢您的任何提示!

答案1

找到了让它工作的方法,但仍然不确定为什么变体 1 不起作用......

问题的关键似乎在于变体 1 中的流#3 没有正确接收,或者 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

相关内容