Linux

在添加或刪除新設備的情況下,網橋上的網路連接中斷

  • September 19, 2018

我目前正在跟踪自定義橋接網路上 docker 容器的連接問題,我可以在不涉及 docker 的情況下將其簡化為 Linux 網路堆棧。

我觀察到的情況如下:我有一個網橋設備,它使用轉發和偽裝連接到外部世界(因此網橋不包含主機的傳出網路介面)。該網橋用於通過長時間執行的程序執行網路操作,該程序僅限於使用網路命名空間和 veth 設備的該網橋(正是 docker 內部所做的)。我們看到的是,每次將(虛擬)網路設備添加到網橋或從網橋中移除時,長時間執行的程序的通信都會中斷。

為了重現我們看到的行為,您可以使用以下程式碼:

#!/bin/bash

set -e

# teardown
function cleanup {
   set +e
   brctl delif brtest vethtest0
   ip link del vethtest0
   iptables -t nat -D POSTROUTING -j MASQUERADE -s 10.12.10.0/24 -d 0.0.0.0/0
   iptables -D FORWARD -i brtest -o enp0s31f6 -j ACCEPT
   iptables -D FORWARD -o brtest -i enp0s31f6 -j ACCEPT
   ip link delete veth0
   ip link set down brtest
   brctl delbr brtest
   ip netns del test
}
trap cleanup EXIT

ip netns add test

brctl addbr brtest
ip addr add 10.12.10.1/24 dev brtest
ip link set up dev brtest

ip link add veth0 type veth peer name veth1
ip link set veth1 netns test
brctl addif brtest veth0
ip link set up dev veth0

ip netns exec test ip addr add 10.12.10.42/24 dev veth1
ip netns exec test ip link set up dev veth1
ip netns exec test ip route add default via 10.12.10.1 dev veth1

# change external interface name
iptables -A FORWARD -o brtest -i enp0s31f6 -j ACCEPT
iptables -A FORWARD -i brtest -o enp0s31f6 -j ACCEPT
iptables -t nat -A POSTROUTING -j MASQUERADE -s 10.12.10.0/24 -d 0.0.0.0/0

while true; do ip netns exec test python3 -c "import socket; socket.gethostbyname('example.org')" && echo success; sleep 1; done

這設置了網橋、veth 設備、網路命名空間和 iptables 規則以復製網路設置,並通過在 while 循環中定期執行(易失性)UDP DNS 請求來模擬長時間執行的過程。

啟動此腳本時,所有 DNS 請求都應該成功,並且您應該success定期看到消息。

要模擬設備加入和離開網橋,您可以在第二個 bash 中啟動以下程式碼:

while true
do
   echo "next"
   ip link add vethtest0 type veth peer name vethtest1
   brctl addif brtest vethtest0
   sleep 2
   brctl delif brtest vethtest0
   ip link del vethtest0
   sleep 1
done

一旦執行,您可以觀察到 DNS 請求會經常延遲,其中一些甚至會失敗。在並行 pcap 中,您會看到有時來自 DNS 查找的 UDP 包不會路由到外部世界,而是最終到達橋接設備而不會離開主機系統。

有人可以解釋這裡發生了什麼以及為什麼向網橋添加和刪除設備會導致連接問題嗎?如何避免它們?

在聯繫了 Linux 核心的 netdev 郵件列表後,Ido Schimmel 提供了解開這個謎團的重要資訊:

網橋的 MAC 地址(在您的範例中為“brtest”)是從具有“最小”MAC 地址的網橋埠繼承的。因此,當您生成具有隨機 MAC 的 veth 設備並將它們從屬於網橋時,您有時也會更改網橋的 MAC 地址。由於網橋是預設網關,因此有時數據包會發送到錯誤的 MAC 地址。

引用自:https://serverfault.com/questions/931474