เรามีข้อกำหนดที่เฉพาะเจาะจงมากซึ่งฉันต้องการแก้ไขด้วย Open vSwitch มันใช้งานได้แล้ว - คุณช่วยแสดงให้ฉันเห็นว่าฉันพลาดอะไรไปบ้าง

ข้อกำหนด:คอนเทนเนอร์ Docker ที่เชื่อมต่อกับอินเทอร์เฟซ mac-vlan แสดงบริการบนพอร์ตเฉพาะ (จำเป็นต้องออกอากาศบนเครือข่ายท้องถิ่น) เราจำเป็นต้องมีบริการที่มีอยู่ในพอร์ตอื่น - และไม่มีวิธีกำหนดค่าพอร์ตที่บริการทำงานอยู่ เราได้ลองใช้วิธีการต่างๆ กันแล้ว (reverse proxy, docker --ports directives เป็นต้น) ซึ่งใช้ไม่ได้ผลด้วยเหตุผลหลายประการ ส่วนใหญ่เป็นเพราะเรายังคงต้องยึดติดกับ IP ของอินเทอร์เฟซ mac-vlan

การตั้งค่าพื้นฐานนั้นค่อนข้างจะแก้ไข เป้าหมายหลักของฉันคือการทำให้มันทำงานแบบนั้น ฉันคิดว่ามันน่าจะเป็นไปได้

สิ่งแวดล้อม: Arch Linux กับเคอร์เนลcore/linux 5.10.9และแพคเกจcommunity/openvswitch 2.14.1-1,community/docker 1:20.10.2-4

ป้อน Open vSwitch:เราได้สร้างอินเทอร์เฟซ mac-vlan บน OVS Bridge และต้องการใช้คำสั่ง 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 and actions=ct(nat) ควรครอบคลุมสิ่งนั้น

ขอบคุณที่อ่านโพสต์ยาวนี้ ฉันขอขอบคุณสำหรับคำแนะนำใด ๆ !

answer

พบวิธีทำให้มันใช้งานได้ ยังไม่แน่ใจว่าทำไมตัวแปร 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