我刚刚开始研究网络命名空间,我正在研究一个非常常见的示例。这只是通过两个 veth 连接两个名称空间(不涉及桥)。
ip netns add net1
ip netns add net2
ip netns exec net1 ifconfig lo up
ip netns exec net2 ifconfig lo up
ip link add veth1 type veth peer name veth2
ip link set veth1 netns net1
ip link set veth2 netns net2
ip netns exec net1 ifconfig veth1 10.0.15.1/24 up
ip netns exec net2 ifconfig veth2 10.0.15.2/24 up
ip netns exec net1 ping 10.0.15.2
输出是:
PING 10.0.15.2 (10.0.15.2) 56(84) bytes of data.
64 bytes from 10.0.15.2: icmp_seq=1 ttl=64 time=0.355 ms
64 bytes from 10.0.15.2: icmp_seq=2 ttl=64 time=0.189 ms
64 bytes from 10.0.15.2: icmp_seq=3 ttl=64 time=0.187 ms
64 bytes from 10.0.15.2: icmp_seq=4 ttl=64 time=0.184 ms
64 bytes from 10.0.15.2: icmp_seq=5 ttl=64 time=0.158 ms
64 bytes from 10.0.15.2: icmp_seq=6 ttl=64 time=0.300 ms
64 bytes from 10.0.15.2: icmp_seq=7 ttl=64 time=0.189 ms
64 bytes from 10.0.15.2: icmp_seq=8 ttl=64 time=0.186 ms
64 bytes from 10.0.15.2: icmp_seq=9 ttl=64 time=0.186 ms
我无法理解的是为什么在我看到的每个例子中,当我们向 veth 提供 IP 时,我们总是给它一个 /24 类 IP。当我尝试给它一个IP时:
ip netns exec net2 ifconfig veth2 10.0.15.2/32 up
我得到的输出是:
PING 10.0.15.2 (10.0.15.2) 56(84) bytes of data.
From 10.0.15.1 icmp_seq=9 Destination Host Unreachable
From 10.0.15.1 icmp_seq=10 Destination Host Unreachable
From 10.0.15.1 icmp_seq=11 Destination Host Unreachable
From 10.0.15.1 icmp_seq=12 Destination Host Unreachable
From 10.0.15.1 icmp_seq=13 Destination Host Unreachable
From 10.0.15.1 icmp_seq=14 Destination Host Unreachable
From 10.0.15.1 icmp_seq=15 Destination Host Unreachable
为什么我无法为其提供单个 IP 地址?
答案1
长话短说
Linux 在添加地址时添加隐式路由。当地址为 /32 时,无法添加隐式路由。然后您需要手动添加到其他 IP 的路由。当它只打算路由到一个目的地(LAN 或 IP,但当它是对称时,通常只路由到对等方的 IP)时,可以缩写为ip address
的peer
参数以在同一镜头中添加路线。因此,不要使用这两个ifconfig
命令,而是使用此命令(使用较新的ip
命令),并且 ping 将起作用:
ip -n net1 link set veth1 up
ip -n net2 link set veth2 up
ip -n net1 address add 10.0.15.1 peer 10.0.15.2 dev veth1
ip -n net2 address add 10.0.15.2 peer 10.0.15.1 dev veth2
更长的答案:
首先说几点:
- 您的问题与网络名称空间无关,而与路由以及 Linux 特性有关。不管怎样,网络命名空间对于整个设置的模型来说非常方便。
- 在 Linux 上,您应该放弃使用该
ifconfig
命令(以及等命令)route
,brctl
以利用由ip路由2。ifconfig
Linux 上的 API (ioctl) 已被放弃一半,转而使用 netlink API,因此某些较新的功能可能只能通过此类ip ...
命令才能使用。 - 最近够了ip路由2工具的大多数子命令都将
-netns
选项作为使用命名空间时的快捷方式:ip -netns net1 FOO
相当于ip netns exec net1 ip FOO
.如果可能的话,我将在下面使用这个快捷方式。许多命令都有缩写版本(例如:ip addr
或者甚至ip a
代替ip address
) 以及一些参数关键字可以省略。我不会在这里使用缩写(除了-n
)-netns
。
当设置带有网络掩码的地址时,Linux 会隐式添加路由。当网络掩码为 /32 时,不能以这种方式添加路由(或者实际上仍然存在:当地的 作用域路由,但它隐藏在当地的路由表 ( ip -n net1 route show table local
) 而不是在主路由表中。当与某些不需要隐式路由的设置ip address add
一起使用标志时,可以防止这种添加。noprefixroute
请注意,ifconfig
还添加了一些默认设置,例如默认(所有主机位设置变体)广播地址。使用时必须明确询问这些ip address
。
以下是一些示例,可帮助您了解正在发生的情况
在添加地址之前,运行ip monitor
在其中一个命名空间中,在一个单独的终端中。它将显示网络命名空间中许多可能的网络更改中的任何一个,然后运行第一个地址添加(ip netns exec net1 ifconfig veth1 10.0.15.1/24 up
)。以下是您通常可以获得的信息:
# ip -4 -n net1 monitor route
local 10.0.15.1 dev veth1 table local proto kernel scope host src 10.0.15.1
broadcast 10.255.255.255 dev veth1 table local proto kernel scope link src 10.0.15.1 linkdown
10.0.0.0/8 dev veth1 proto kernel scope link src 10.0.15.1 linkdown
broadcast 10.0.0.0 dev veth1 table local proto kernel scope link src 10.0.15.1 linkdown
Deleted 10.0.0.0/8 dev veth1 proto kernel scope link src 10.0.15.1 linkdown
Deleted broadcast 10.255.255.255 dev veth1 table local proto kernel scope link src 10.0.15.1 linkdown
Deleted broadcast 10.0.0.0 dev veth1 table local proto kernel scope link src 10.0.15.1 linkdown
Deleted local 10.0.15.1 dev veth1 table local proto kernel scope host src 10.0.15.1
local 10.0.15.1 dev veth1 table local proto kernel scope host src 10.0.15.1
broadcast 10.0.15.255 dev veth1 table local proto kernel scope link src 10.0.15.1 linkdown
10.0.15.0/24 dev veth1 proto kernel scope link src 10.0.15.1 linkdown
broadcast 10.0.15.0 dev veth1 table local proto kernel scope link src 10.0.15.1 linkdown
这里看来ifconfig
工作效率低下:它首先添加 /8 路由,然后将其删除并放置所请求的 /24 路由。这可能是过去从未纠正过的遗留问题。这相当于ip -n net1 link set veth1 up; ip -n net1 address add 10.0.15.1/24 broadcast + dev veth1
:
local 10.0.15.1 dev veth1 table local proto kernel scope host src 10.0.15.1
broadcast 10.0.15.255 dev veth1 table local proto kernel scope link src 10.0.15.1 linkdown
10.0.15.0/24 dev veth1 proto kernel scope link src 10.0.15.1 linkdown
broadcast 10.0.15.0 dev veth1 table local proto kernel scope link src 10.0.15.1 linkdown
如果您不需要 /24 怎么办?您可以设置 /32 IP 并自己添加路由,如下所示(同时我重写了整个设置的(可以说)较短版本):
ip netns add net1
ip netns add net2
ip -n net1 link set lo up
ip -n net2 link set lo up
ip -n net1 link add name veth1 type veth peer netns net2 name veth2
设置接口(可以在之前或之后完成,一旦启动就不会改变最终结果):
ip -n net1 link set veth1 up
ip -n net2 link set veth2 up
地址:
ip -n net1 address add 10.0.15.1/32 dev veth1
ip -n net2 address add 10.0.15.2/32 dev veth2
这里 anip -4 -n net1 monitor route
只会显示local 10.0.15.1 dev veth1 table local proto kernel scope host src 10.0.15.1
:仅隐藏的本地路由。
路线:
ip -n net1 route add 10.0.15.2/32 dev veth1
ip -n net2 route add 10.0.15.1/32 dev veth2
这两个地址值可以完全不相关。您同样可以使用 192.0.2.1 和 198.51.100.2。一些托管提供商使用此机制来提供额外的“故障转移 IP”。其实这种具体情况有一个捷径,只要提供相关信息,就会沿着地址一次性添加一条路线。因此,代替前面的 4 个命令,这已经足够了:
ip -n net1 address add 10.0.15.1 peer 10.0.15.2 dev veth1
ip -n net2 address add 10.0.15.2 peer 10.0.15.1 dev veth2
请注意,在所有情况下,这些接口仍然是以太网接口,而不是点对点,因此仍然会在链路层发出 ARP 请求来查找其他 IP。
最后注意事项:如果您打算一起使用两个以上的网络命名空间,您可能应该恢复使用 LAN 网络掩码,并且您很可能需要创建一个桥接接口(您可以将其放在原始命名空间中,其中之一)新创建的命名空间,但我建议您将其放在自己的保留命名空间中,以避免不可预见的交互)。然后,对于每对 veth 接口,一侧应放入网桥的网络命名空间中并从属于网桥(例如:ip -n mybridgens link set vethp1 master bridge0
)。