我需要建立一个网络环境,其中两个 veth 接口连接到一个网桥,并且它们需要能够相互通信。
所以我在干净的 ubuntu shell 中执行以下命令:
# Create Two veth and attach them to the bridge
sudo ip link add veth0 type veth peer name veth0p
sudo ip link add veth1 type veth peer name veth1p
sudo brctl addbr br0
sudo brctl addif br0 veth0p
sudo brctl addif br0 veth1p
# Set links up
sudo ip link set veth0 up
sudo ip link set veth1 up
sudo ip link set veth0p up
sudo ip link set veth1p up
sudo ip link set br0 up
# Give each veth an IP address
sudo ip addr add 10.0.0.1/24 dev veth0
sudo ip addr add 10.0.0.2/24 dev veth1
# Try to ping one from the other
ping 10.0.0.1 -I veth1
ping 不起作用。有人能帮我解决这个问题吗?我应该怎么做veth0
才能veth2
互相 ping 通?
的输出ip r s
是:
default via 192.168.0.1 dev ens160 proto dhcp src 192.168.0.119 metric 100
10.0.0.0/24 dev veth0 proto kernel scope link src 10.0.0.1
10.0.0.0/24 dev veth1 proto kernel scope link src 10.0.0.2
192.168.0.0/24 dev ens160 proto kernel scope link src 192.168.0.119
192.168.0.1 dev ens160 proto dhcp scope link src 192.168.0.119 metric 100
这样做的目的是veth
稍后将这两个接口放入 VXLAN 覆盖网络中。但出于开发目的,我想测试此时未设置 VXLAN 的网桥和两个接口。 (但即使没有设置 VXLAN,只要它们位于同一网桥上,它们就应该能够互相 ping 通,对吧?)
谢谢你!
答案1
路由应该发生在多个系统之间,每个系统都有自己的网络堆栈:在多个网络堆栈之间。
没有兴趣让这个测试在单身的网络堆栈。让它像这样工作需要进行许多调整,最终结果根本不会反映与预期目标类似的配置,并且对于开发此类项目没有用处。
在 Linux 上执行此操作的最简单正确方法是使用网络命名空间(或容器)
使用OP的设置,然后接口被移动到两个命名空间(使用创建ip netns add
)。由于这会触发接口上的配置丢失,因此请重新添加丢失的内容。这样根用户,在 OP 设置后(减去无论如何都会丢失的地址分配):
ip netns add system1
ip netns add system2
ip link set dev veth0 netns system1
ip link set dev veth1 netns system2
ip -n system1 link set lo up # this is optional for this problem
ip -n system2 link set lo up # this is optional for this problem
ip -n system1 address add 10.0.0.1/24 dev veth0
ip -n system2 address add 10.0.0.2/24 dev veth1
ip -n system1 link set dev veth0 up
ip -n system2 link set dev veth1 up
现在一切都很简单了。系统1和系统2模拟系统,因为它们将在真正的最终设置中使用。下面的命令将成功并遵循正常的路由行为,正如通过交换机在真实系统中所预期的那样:
ip netns exec system1 ping 10.0.0.2
注意:通过最初创建如下接口,可以在没有桥接的情况下缩短整个特定设置(仅具有两个对等点):ip link add name veth0 type veth peer name veth1
。桥接器不是问题的一部分,但一旦必须模拟第三个对等系统,就肯定需要桥接器。
好奇者的奖励:严格回答问题
目标:让主机通过线路(而不是通过lo
接口)对自身进行 ping 操作。再次警告,即使这有效,结果也不能用于任何有用的事情,包括模拟多个系统。
所以这是通过 OP 的初始设置完成的,没有网络命名空间。
与一个单身的网络堆栈必须进行一些调整。下面有很多细节,因为这些细节妨碍了它正常工作。
系统必须Accept接收源IP地址属于自己的数据包而不是丢掉它
sysctl -w net.ipv4.conf.veth0.accept_local=1 sysctl -w net.ipv4.conf.veth1.accept_local=1
同一个数据包会被看到两次,一次是发出时,一次是收到时,这两种情况需要不同的(基于策略的)路由。
系统必须区分数据包是本地创建并发送的情况
veth0
与该数据包随后从外部接收的情况。veth1
与通过线路。这就需要两个不同的策略路由规则选择两个不同的路由表。如果方向相反,则总共会形成 4 条规则和 4 个表格。实际上当地的路由表已经包含其中的一半(对于接收的数据包:用于主机),因此只有本地发出的数据包需要特殊的路由规则和表。政策规则:
ip rule add priority 11 iif lo from 10.0.0.1 lookup 1001 ip rule add priority 21 iif lo from 10.0.0.2 lookup 2001
特殊
iif lo
意味着本地发起的流量(实际上并不是从接口接收lo
)。关联的路由表各有其单一路由:
ip route add 10.0.0.2 dev veth0 table 1001 ip route add 10.0.0.1 dev veth1 table 2001
这当地的路由表妨碍了
到目前为止我们有:
# ip rule 0: from all lookup local 11: from 10.0.0.1 iif lo lookup 1001 21: from 10.0.0.2 iif lo lookup 2001 32766: from all lookup main 32767: from all lookup default # ip route show table local to root 10.0.0.0/24 local 10.0.0.1 dev veth0 proto kernel scope host src 10.0.0.1 local 10.0.0.2 dev veth1 proto kernel scope host src 10.0.0.2 broadcast 10.0.0.255 dev veth0 proto kernel scope link src 10.0.0.1 broadcast 10.0.0.255 dev veth1 proto kernel scope link src 10.0.0.2
这当地的表具有最低优先级值规则并首先使用。前两个条目首先匹配并覆盖附加规则(优先级 11 和 21)和路由,从而将数据包保持在本地(即:使用接口
lo
)。人们可以删除这些条目,但正如上面所写,它们实际上是需要的,但只有在添加策略规则之后才需要。此外,更改接口上的地址迟早会让内核将它们添加回来。
因此,我们可以将
from all lookup local
规则移动到更高的优先级值,让添加的优先级为 11 和 21 的规则首先遍历,以首先获取特殊路由:ip rule add priority 50 lookup local ip rule del priority 0
人们可以检查单个 ping 所遵循的路由及其答案:
初始数据包是
veth0
使用时强制通过ping -I veth0 10.0.0.2
:# ip route get oif veth0 to 10.0.0.2 10.0.0.2 dev veth0 src 10.0.0.1 uid 0 cache
或者在使用时将其源 IP 地址绑定到 10.0.0.1
ping -I 10.0.0.1 10.0.0.2
:# ip route get from 10.0.0.1 to 10.0.0.2 10.0.0.2 from 10.0.0.1 dev veth0 table 1001 uid 0 cache
两种情况的路由相同(尽管使用不同的路由表)。
该数据包(穿过网桥(请参阅稍后有关 ARP 的警告)并且)现在在另一端收到veth1
:
# ip route get from 10.0.0.1 iif veth1 to 10.0.0.2
local 10.0.0.2 from 10.0.0.1 dev lo table local
cache <local> iif veth1
回复使用源地址 10.0.0.2 发送回目标 10.0.0.1:
# ip route get from 10.0.0.2 to 10.0.0.1
10.0.0.1 from 10.0.0.2 dev veth1 table 2001 uid 0
cache
并在以下时间收到答复(穿过桥并)veth0
:
# ip route get from 10.0.0.2 iif veth0 to 10.0.0.1
local 10.0.0.1 from 10.0.0.2 dev lo table local
cache <local> iif veth0
平轮预计将顺利完成。
发出并解决 ARP 请求:
# ip neigh
10.0.0.1 dev veth1 lladdr f2:2a:75:82:17:d3 DELAY
10.0.0.2 dev veth0 lladdr 42:91:a1:a6:64:45 REACHABLE
10.0.0.1 dev br0 lladdr f2:2a:75:82:17:d3 STALE
可以看出,桥接自身接口br0
尽管没有配置地址,但由于 Linux 的 Weak 实现,它仅仅存在于同一个网络堆栈中,也参与了 ARP 和路由。主机型号。以上42:91:a1:a6:64:45
来自br0
(继承自veth1p
)。因此,前几个 ping 最初可以路由为veth0
-> br0
(+ 回复为veth1
-> veth0
) 而不是veth0
-> veth1
(+ veth1
-> veth0
),并在几秒钟后一旦暂时获知的 ARP 条目过期就恢复到正确的流。
br0
可以通过多种方式阻止参与路由,其中:
-
sysctl -w net.ipv4.conf.br0.arp_ignore=1
或通过激活
rp_filter
(为了严格反向路径转发),这样它也不会回复 ARP:sysctl -w net.ipv4.conf.br0.rp_filter=1
或者如果 Linux 系统支持网桥 VLAN 过滤,则将网桥的自身接口与网桥端口隔离:
ip link set dev br0 type bridge vlan_filtering 1 bridge vlan del vid 1 dev br0 self
这会在默认配置中将网桥的自身接口与它自己的网桥端口的通信分离,从而通过它堵住本地网络堆栈的“泄漏”。 (在这种情况下,
tcpdump -i br0 -p
使用不将其设置为混杂模式的选项进行捕获也-p
将不再接收任何流量)。
同样,这种小故障在实际情况下不会发生,因为桥接器可能位于其他地方(例如:真正的交换机、其他虚拟机或其他网络命名空间/容器)。