namespace是Linux虚拟网络的一个重要概念,传统的Linux的许多资源是全局的,如果进程id资源。而namespace的目的首先就是讲这些资源做资源隔离。Linux可以在一个Host内创建许多namespace,于是那些原本是linux的全局资源,就变成了namespace范围内的“全局”资源,而且不同namespace的资源相互不可见,彼此透明。
Linux namespace 可以隔离的资源有:uts_ns(内存、版本等底层信息)、ipc_ns(所有与进程通信的信息)、 mnt_ns(当前装载的文件系统)、 pid_ns(有关进程id的信息)、 user_ns(资源配额的信息)、 net_ns(网络信息)。
一个设备(Linux Device)只能位于一个namespace中,不同namespace中的设备可以利用veth pair进行桥接。
Linux 操作namespace的命令是ip netns。
[root@virtual ~]# ip netns help
Usage: ip netns list
ip netns add NAME
ip netns set NAME NETNSID
ip [-all] netns delete [NAME]
ip netns identify [PID]
ip netns pids NAME
ip [-all] netns exec [NAME] cmd ...
ip netns monitor
ip netns list-id
[root@virtual ~]#
首先创建一个namespace:
# 查看namespace列表
[root@virtual ~]# ip netns list
[root@virtual ~]#
# 新增 namespace ns_test
[root@virtual ~]# ip netns add ns_test
[root@virtual ~]#
[root@virtual ~]# ip netns list
ns_test
[root@virtual ~]#
当创建一个namespace后,就可以将一些虚拟设备迁移到这个namespace中去了,比如上一篇中介绍的tap。
# 创建tap,并配置对应IP,详细信息可看上一篇文档
[root@virtual ~]# tunctl -t tap_test
Set 'tap_test' persistent and owned by uid 0
[root@virtual ~]# ip link list
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
link/ether fa:16:3e:56:6a:87 brd ff:ff:ff:ff:ff:ff
3: tap_test: mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
link/ether 2e:5c:3f:10:63:12 brd ff:ff:ff:ff:ff:ff
[root@virtual ~]# ip addr show
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether fa:16:3e:56:6a:87 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.176/24 brd 10.0.0.255 scope global noprefixroute dynamic eth0
valid_lft 75898sec preferred_lft 75898sec
inet6 fe80::f816:3eff:fe56:6a87/64 scope link
valid_lft forever preferred_lft forever
3: tap_test: mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 2e:5c:3f:10:63:12 brd ff:ff:ff:ff:ff:ff
[root@virtual ~]# ip addr add local 10.0.0.190/24 dev tap_test
[root@virtual ~]# ip a show
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether fa:16:3e:56:6a:87 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.176/24 brd 10.0.0.255 scope global noprefixroute dynamic eth0
valid_lft 75813sec preferred_lft 75813sec
inet6 fe80::f816:3eff:fe56:6a87/64 scope link
valid_lft forever preferred_lft forever
3: tap_test: mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 2e:5c:3f:10:63:12 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.190/24 scope global tap_test
valid_lft forever preferred_lft forever
[root@virtual ~]#
# 创建namespace后,将前面创建的tap_test迁移到这个namespace中。
# 迁移之后,在外直接 ip a s 已经看不到这个虚拟设备了
[root@virtual ~]#
[root@virtual ~]# ip link set tap_test netns ns_test
[root@virtual ~]#
[root@virtual ~]# ip netns exec ns_test ip a s
1: lo: mtu 65536 qdisc noop state DOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: tap_test: mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 2e:5c:3f:10:63:12 brd ff:ff:ff:ff:ff:ff
[root@virtual ~]# ip netns exec ns_test ip addr add 192.168.10.190/24 dev tap_test
[root@virtual ~]# ip netns exec ns_test ip a s
1: lo: mtu 65536 qdisc noop state DOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: tap_test: mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 2e:5c:3f:10:63:12 brd ff:ff:ff:ff:ff:ff
inet 192.168.10.190/24 scope global tap_test
valid_lft forever preferred_lft forever
[root@virtual ~]#
veth pair 不是一个设备,而是一对设备,以连接两个虚拟以太端口。操作veth pair,需要跟namespace一起配合,不然就没有意义。
两个namespace ns1/ns2 中各有一个tap组成veth pair,两个tap 上配置的ip进行互ping。
# 创建 veth pair
[root@virtual ~]# ip link add tap1 type veth peer name tap2
[root@virtual ~]# ip a s
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether fa:16:3e:56:6a:87 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.176/24 brd 10.0.0.255 scope global noprefixroute dynamic eth0
valid_lft 64021sec preferred_lft 64021sec
inet6 fe80::f816:3eff:fe56:6a87/64 scope link
valid_lft forever preferred_lft forever
6: tap2@tap1: mtu 1500 qdisc noop state DOWN qlen 1000
link/ether a6:74:e9:cb:8f:f1 brd ff:ff:ff:ff:ff:ff
7: tap1@tap2: mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 02:d1:8c:8b:44:e9 brd ff:ff:ff:ff:ff:ff
[root@virtual ~]#
# 创建namespace,并将tap迁移至namespace中:
[root@virtual ~]# ip netns add ns1
[root@virtual ~]# ip netns add ns2
[root@virtual ~]# ip link set tap1 netns ns1
[root@virtual ~]# ip link set tap2 netns ns2
[root@virtual ~]# ip netns exec ns1 ip addr add local 192.168.10.200/24 dev tap1
[root@virtual ~]# ip netns exec ns2 ip addr add local 192.168.10.201/24 dev tap2
[root@virtual ~]# ip netns exec ns1 ifconfig tap1 up
[root@virtual ~]# ip netns exec ns2 ifconfig tap2 up
[root@virtual ~]#
[root@virtual ~]# ip link list
1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
link/ether fa:16:3e:56:6a:87 brd ff:ff:ff:ff:ff:ff
[root@virtual ~]# ip netns list
ns2
ns1 (id: 0)
ns_test
[root@virtual ~]#
[root@virtual ~]# ip netns exec ns1 ping 192.168.10.201
PING 192.168.10.201 (192.168.10.201) 56(84) bytes of data.
64 bytes from 192.168.10.201: icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 192.168.10.201: icmp_seq=2 ttl=64 time=0.027 ms
64 bytes from 192.168.10.201: icmp_seq=3 ttl=64 time=0.026 ms
64 bytes from 192.168.10.201: icmp_seq=4 ttl=64 time=0.023 ms
^C
--- 192.168.10.201 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.023/0.026/0.028/0.002 ms
[root@virtual ~]# ip netns exec ns1 ip a
1: lo: mtu 65536 qdisc noop state DOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
7: tap1@if6: mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 02:d1:8c:8b:44:e9 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 192.168.10.200/24 scope global tap1
valid_lft forever preferred_lft forever
inet6 fe80::d1:8cff:fe8b:44e9/64 scope link
valid_lft forever preferred_lft forever
[root@virtual ~]# ip netns exec ns2 ip a s
1: lo: mtu 65536 qdisc noop state DOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: tap2@if7: mtu 1500 qdisc noqueue state UP qlen 1000
link/ether a6:74:e9:cb:8f:f1 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.10.201/24 scope global tap2
valid_lft forever preferred_lft forever
inet6 fe80::a474:e9ff:fecb:8ff1/64 scope link
valid_lft forever preferred_lft forever
[root@virtual ~]#
通过以上的测试用例,可以了解通过veth pair连接两个namespace的方法。
后面会有依靠Bridge/Switch 实现三个或多个namespace进行互通。
在Linux的语境中,Bridge和Switch是一个概念。Bridge是一个虚拟网络设备,所以具有网络设备的特征,可以配置IP、MAC地址等;Bridge是一个虚拟交换机,和物理交换机有类似的功能。对于普通的网络设备来说,只有两端,从一端进来的数据会从另一端出去,如物理网卡从外面网络中收到的数据会转发给内核协议栈,而从协议栈过来的数据会转发到外面的物理网络中。 而Bridge不同,Bridge有多个端口,数据可以从任何端口进来,进来之后从哪个口出去和物理交换机的原理差不多,要看mac地址。
Linux实现Bridge功能是brctl模块。可以直接在命令行上查看,如果没有回显的话,可直接使用yum进行安装。
[root@virtual ~]# brctl
-bash: brctl: command not found
[root@virtual ~]# yum -y install bridge-utils
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
......
Running transaction
Installing : bridge-utils-1.5-9.el7.x86_64 1/1
Verifying : bridge-utils-1.5-9.el7.x86_64 1/1
Installed:
bridge-utils.x86_64 0:1.5-9.el7
Complete!
[root@virtual ~]# brctl
Usage: brctl [commands]
commands:
addbr add bridge
delbr delete bridge
addif add interface to bridge
delif delete interface from bridge
hairpin {on|off} turn hairpin on/off
setageing <time> set ageing time
setbridgeprio set bridge priority
setfd <time> set bridge forward delay
sethello <time> set hello time
setmaxage <time> set max message age
setpathcost set path cost
setportprio set port priority
show [ ] show a list of bridges
showmacs show a list of mac addrs
showstp show bridge stp info
stp {on|off} turn stp on/off
[root@virtual ~]#
根据如下拓扑图,我们模拟创建相应的虚拟网络设备,进行实现:
命令操作:
# 创建对于设备
[root@virtual ~]# ip link add tap1 type veth peer name tap1_peer
[root@virtual ~]# ip link add tap2 type veth peer name tap2_peer
[root@virtual ~]# ip link add tap3 type veth peer name tap3_peer
[root@virtual ~]# ip link add tap4 type veth peer name tap4_peer
[root@virtual ~]#
[root@virtual ~]# ip a s | grep tap
8: tap1_peer@tap1: mtu 1500 qdisc noop state DOWN qlen 1000
9: tap1@tap1_peer: mtu 1500 qdisc noop state DOWN qlen 1000
10: tap2_peer@tap2: mtu 1500 qdisc noop state DOWN qlen 1000
11: tap2@tap2_peer: mtu 1500 qdisc noop state DOWN qlen 1000
12: tap3_peer@tap3: mtu 1500 qdisc noop state DOWN qlen 1000
13: tap3@tap3_peer: mtu 1500 qdisc noop state DOWN qlen 1000
14: tap4_peer@tap4: mtu 1500 qdisc noop state DOWN qlen 1000
15: tap4@tap4_peer: mtu 1500 qdisc noop state DOWN qlen 1000
[root@virtual ~]#
[root@virtual ~]# ip netns list
ns_test
[root@virtual ~]# ip netns add ns1
[root@virtual ~]# ip netns add ns2
[root@virtual ~]# ip netns add ns3
[root@virtual ~]# ip netns add ns4
[root@virtual ~]# ip netns list
ns4
ns3
ns2
ns1
ns_test
[root@virtual ~]#
# 将设备迁移至namespace
[root@virtual ~]# ip link set tap1 netns ns1
[root@virtual ~]# ip link set tap2 netns ns2
[root@virtual ~]# ip link set tap3 netns ns3
[root@virtual ~]# ip link set tap4 netns ns4
[root@virtual ~]#
# 创建 Bridge
[root@virtual ~]# brctl addbr br1
[root@virtual ~]# ip a s | grep br1
17: br1: mtu 1500 qdisc noop state DOWN qlen 1000
[root@virtual ~]#
# 将tap 添加到 Bridge中
[root@virtual ~]# brctl addif br1 tap1_peer
[root@virtual ~]# brctl addif br1 tap2_peer
[root@virtual ~]# brctl addif br1 tap3_beer
interface tap3_beer does not exist!
[root@virtual ~]# brctl addif br1 tap3_peer
[root@virtual ~]# brctl addif br1 tap4_peer
[root@virtual ~]#
# 配置 tap 对应的ip地址
[root@virtual ~]# ip netns exec ns1 ip addr add local 192.168.10.200/24 dev tap1
[root@virtual ~]# ip netns exec ns2 ip addr add local 192.168.10.201/24 dev tap2
[root@virtual ~]# ip netns exec ns3 ip addr add local 192.168.10.202/24 dev tap3
[root@virtual ~]# ip netns exec ns4 ip addr add local 192.168.10.203/24 dev tap4
[root@virtual ~]#
# 将 Bridge 以及所有 tap 状态设置为 up
[root@virtual ~]# ip link set br1 up
[root@virtual ~]# ip link set tap1_peer up
[root@virtual ~]# ip link set tap2_peer up
[root@virtual ~]# ip link set tap3_peer up
[root@virtual ~]# ip link set tap4_peer up
[root@virtual ~]# ip netns exec ns1 ip link set tap1 up
[root@virtual ~]# ip netns exec ns2 ip link set tap2 up
[root@virtual ~]# ip netns exec ns3 ip link set tap3 up
[root@virtual ~]# ip netns exec ns4 ip link set tap4 up
[root@virtual ~]#
# 相互进行ip 互ping ,验证网络连通
[root@virtual ~]# ip netns exec ns1 ping 192.168.10.201
PING 192.168.10.201 (192.168.10.201) 56(84) bytes of data.
64 bytes from 192.168.10.201: icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from 192.168.10.201: icmp_seq=2 ttl=64 time=0.032 ms
64 bytes from 192.168.10.201: icmp_seq=3 ttl=64 time=0.031 ms
64 bytes from 192.168.10.201: icmp_seq=4 ttl=64 time=0.027 ms
^C
--- 192.168.10.201 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.027/0.032/0.041/0.008 ms
[root@virtual ~]# ip netns exec ns1 ping 192.168.10.202
PING 192.168.10.202 (192.168.10.202) 56(84) bytes of data.
64 bytes from 192.168.10.202: icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from 192.168.10.202: icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 192.168.10.202: icmp_seq=3 ttl=64 time=0.037 ms
64 bytes from 192.168.10.202: icmp_seq=4 ttl=64 time=0.027 ms
^C
--- 192.168.10.202 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.027/0.034/0.041/0.007 ms
[root@virtual ~]# ip netns exec ns1 ping 192.168.10.203
PING 192.168.10.203 (192.168.10.203) 56(84) bytes of data.
64 bytes from 192.168.10.203: icmp_seq=1 ttl=64 time=0.059 ms
64 bytes from 192.168.10.203: icmp_seq=2 ttl=64 time=0.027 ms
64 bytes from 192.168.10.203: icmp_seq=3 ttl=64 time=0.033 ms
64 bytes from 192.168.10.203: icmp_seq=4 ttl=64 time=0.031 ms
^C
--- 192.168.10.203 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.027/0.037/0.059/0.014 ms
[root@virtual ~]#
[root@virtual ~]# ip netns exec ns4 ping 192.168.10.200
PING 192.168.10.200 (192.168.10.200) 56(84) bytes of data.
64 bytes from 192.168.10.200: icmp_seq=1 ttl=64 time=0.022 ms
64 bytes from 192.168.10.200: icmp_seq=2 ttl=64 time=0.024 ms
64 bytes from 192.168.10.200: icmp_seq=3 ttl=64 time=0.033 ms
64 bytes from 192.168.10.200: icmp_seq=4 ttl=64 time=0.030 ms
^X^C
--- 192.168.10.200 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.022/0.027/0.033/0.005 ms
[root@virtual ~]#