我正在容器内工作,试图演示 Linux 桥接器和第 2 层连接。
我启动了一个新容器:
host$ docker run -it --rm --name c1 --privileged networking sh
在容器上我使用下面的命令创建桥接接口和 tap 接口
c1$ ip link add br0 type bridge
c1$ ip link set eth0 master br0
c1$ ip tuntap add tap0 mode tap
c1$ ip link set tap0 master br0
c1$ ip link set tap0 up
c1$ ip link set br0 up
c1$ ping -I tap0 172.17.0.2
最后一个 ping 命令不起作用。我做错了什么?tap 接口是正确的接口吗?如何使用 Linux Bridge 在容器上显示第 2 层连接?
根据@grawity 的回答,我尝试了以下操作:
ip link add dev veth1 type veth peer name veth2
ip link set dev veth1 up
ip link add br0 type bridge
ip link set veth1 master br0
ip link set eth0 master br0
ip link set br0 up
ip link set veth1 up
ip link set veth2 up
ip addr add 10.0.0.3/24 dev veth1
ip addr add 10.0.0.4/24 dev veth2
ip addr add 10.0.0.2/24 dev br0
/ # brctl show
bridge name bridge id STP enabled interfaces
br0 8000.0242ac110002 no veth1
eth0
ping 所有接口都有效
/ # ping -c1 10.0.0.2
PING 10.0.0.2 (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.068 ms
--- 10.0.0.2 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.068/0.068/0.068 ms
/ # ping -c1 10.0.0.3
PING 10.0.0.3 (10.0.0.3): 56 data bytes
64 bytes from 10.0.0.3: seq=0 ttl=64 time=0.072 ms
--- 10.0.0.3 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.072/0.072/0.072 ms
/ # ping -c1 10.0.0.4
PING 10.0.0.4 (10.0.0.4): 56 data bytes
64 bytes from 10.0.0.4: seq=0 ttl=64 time=0.095 ms
--- 10.0.0.4 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.095/0.095/0.095 ms
从 veth2 到 eth0 的 ping 和 arping 均不起作用。
ping -I veth2 -c1 172.17.0.2
ip 链接输出
10: veth2@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000\ link/ether f2:8e:e4:f7:fc:7c brd ff:ff:ff:ff:ff:ff
11: veth1@veth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP mode DEFAULT group default qlen 1000\ link/ether 1a:3a:26:02:8a:a1 brd ff:ff:ff:ff:ff:ff
12: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000\ link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP mode DEFAULT group default \ link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
和 ip 输出
/ # ip -o a
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
1: lo inet6 ::1/128 scope host \ valid_lft forever preferred_lft forever
10: veth2 inet 10.0.0.4/24 scope global veth2\ valid_lft forever preferred_lft forever
10: veth2 inet6 fe80::f08e:e4ff:fef7:fc7c/64 scope link \ valid_lft forever preferred_lft forever
11: veth1 inet 10.0.0.3/24 scope global veth1\ valid_lft forever preferred_lft forever
11: veth1 inet6 fe80::183a:26ff:fe02:8aa1/64 scope link \ valid_lft forever preferred_lft forever
12: br0 inet 10.0.0.2/24 scope global br0\ valid_lft forever preferred_lft forever
12: br0 inet6 fe80::42:acff:fe11:2/64 scope link \ valid_lft forever preferred_lft forever
21: eth0 inet 172.17.0.2/16 scope global eth0\ valid_lft forever preferred_lft forever
21: eth0 inet6 fe80::42:acff:fe11:2/64 scope link \ valid_lft forever preferred_lft forever
tcpdump 具有以下内容
09:29:31.253321 ARP, Request who-has 6e2b9b27d81b (Broadcast) tell 10.0.0.4, length 28
09:29:31.253509 ARP, Request who-has 172.17.0.1 tell 6e2b9b27d81b, length 28
09:29:31.253541 ARP, Reply 172.17.0.1 is-at 02:42:be:d6:a7:81 (oui Unknown), length 28
09:29:31.253541 ARP, Reply 172.17.0.1 is-at 02:42:be:d6:a7:81 (oui Unknown), length 28
09:29:36.263281 ARP, Request who-has 172.17.0.1 tell 6e2b9b27d81b, length 28
09:29:36.263313 ARP, Reply 172.17.0.1 is-at 02:42:be:d6:a7:81 (oui Unknown), length 28
09:29:36.263313 ARP, Reply 172.17.0.1 is-at 02:42:be:d6:a7:81 (oui Unknown), length 28
09:29:36.268142 ARP, Request who-has 6e2b9b27d81b (Broadcast) tell 10.0.0.4, length 28
09:29:41.284187 ARP, Request who-has 6e2b9b27d81b (Broadcast) tell 10.0.0.4, length 28
09:29:41.284196 ARP, Request who-has 6e2b9b27d81b (Broadcast) tell 10.0.0.4, length 28
我错过了什么?是什么6e2b9b27d81b
?
答案1
首先:您的接口没有配置 IP 地址,因此如果没有地址,您就无法通过它真正发送和接收 IP 数据包。(ping
使用 ICMP,一种 IP 协议。)
第二:Tap 接口的工作方式并非如此——它们不会将ping
数据包“反射”回网桥;相反,它们希望连接到程序,例如 OpenVPN 或其他 VPN 软件。
因此,如果您尝试设置桥接到主机网络(共享单个子网)的 OpenVPN,您的方法将有效。但如果您只是想了解 Linux 桥接器的工作原理,那么使用veth
接口会更好。
如果你想要的只是与外部 LAN 建立 L2 连接,那么你就在错误的地方创建了网桥——这种事情通常在主持人,不在容器中。
可以将网络接口想象为具有两端:“主机”端显示在操作系统中,并由所有软件使用;另一端连接到实际网络(例如物理以太网端口)。如果数据包从一端进入,它们将通过其他结束。(当然,网桥可以有多个端口,而不只是两个,但适用相同的一般原则。)
当你桥接一个接口时,网桥接管主持人该接口的一侧,因此它只能看到来自从网络。但是,如果您使用ping -I eth0
或ping -I tap0
,则会绕过桥接器并将所有内容发送到实际网络。
ping ──› [eth0 ──› NIC] ──› network
ping ──› [tap0 ──› VPN software] ──› ???
┌─› [eth0 ──› NIC] ──› network
ping ──› br0 ──┤
└─› [tap0 ──› VPN software] ──› ???
∧
ping -I tap0 ───┘
因此,在您的情况下,tap 接口毫无用处 - 您尝试通过它发送的所有数据包都将被丢弃,因为另一端没有附加任何程序。(如果您检查,ip link
您可能会看到带有NO-CARRIER
标志的数据包。)
例如,您可以使用veth
接口(与容器经常使用的接口相同)——它们总是成对创建并相互连接。因此,如果您指示ping
通过 发送数据包veth0
,它们将回环并通过 的主机端veth1
,桥接器可以接收它们并在必要时通过 eth0 转发。
┌── [eth0 ──› NIC] ──› network
br0 ──┤
└── [veth1 ‹───› veth0] ‹── ping -I veth0