阅读计划-Linux虚拟网络设备

Posted by 聪少 on 2019-06-11

Linux是通过虚拟网络设备去操作和使用网卡的。系统安装了一个网卡之后会为其生成一个网络设备实例(如eth0)。随着网络虚拟化技术的发展,Linux支持创建虚拟化设备。常见的虚拟化设备有Veth、Bridge、802.1.q VLAN device、TAP。

Linux Veth

Veth是成对出现的虚拟网络设备,发送到Veth一端虚拟设备的请求会从另一端的虚拟设备中发出。在容器环境中经常会使用Veth连接不同网络namespace。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 创建network namespace
[root@tyy ~]# ip netns add ns1
[root@tyy ~]# ip netns add ns2
# network namespace列表
[root@tyy ~]# ip netns list
ns2
ns1
# 创建一对veth设备
[root@tyy ~]# ip link add veth0 type veth peer name veth1
# 将两个veth0分别添加到ns1和ns2中
[root@tyy ~]# ip link set veth0 netns ns1
[root@tyy ~]# ip link set veth1 netns ns2
# 分别查看两个ns中到设备信息
[root@tyy ~]# ip netns exec ns1 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
6: veth0@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
link/ether 0a:07:9b:21:a3:b4 brd ff:ff:ff:ff:ff:ff link-netnsid 1
[root@tyy ~]# ip netns exec ns2 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
link/ether 42:cc:d5:e7:43:cd brd ff:ff:ff:ff:ff:ff link-netnsid 0
# 配置IP
[root@tyy ~]# ip netns exec ns1 ifconfig veth0 172.18.0.2/24 up
[root@tyy ~]# ip netns exec ns2 ifconfig veth1 172.18.0.3/24 up
# 检查IP
[root@tyy ~]# ip netns exec ns2 ifconfig
veth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.0.3 netmask 255.255.255.0 broadcast 172.18.0.255
inet6 fe80::40cc:d5ff:fee7:43cd prefixlen 64 scopeid 0x20<link>
ether 42:cc:d5:e7:43:cd txqueuelen 1000 (Ethernet)
RX packets 10 bytes 796 (796.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 10 bytes 796 (796.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

[root@tyy ~]# ip netns exec ns1 ifconfig
veth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.0.2 netmask 255.255.255.0 broadcast 172.18.0.255
inet6 fe80::807:9bff:fe21:a3b4 prefixlen 64 scopeid 0x20<link>
ether 0a:07:9b:21:a3:b4 txqueuelen 1000 (Ethernet)
RX packets 10 bytes 796 (796.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 10 bytes 796 (796.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# 配置路由
[root@tyy ~]# ip netns exec ns1 route add default dev veth0
[root@tyy ~]# ip netns exec ns2 route add default dev veth1
# 测试
# ping
[root@tyy ~]# ip netns exec ns1 ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.027 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.049 ms
64 bytes from 172.18.0.3: icmp_seq=3 ttl=64 time=0.050 ms
64 bytes from 172.18.0.3: icmp_seq=4 ttl=64 time=0.043 ms
# 抓包

[root@tyy ~]# ip netns exec ns2 tcpdump -i veth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1, link-type EN10MB (Ethernet), capture size 262144 bytes
16:11:30.657488 IP 172.18.0.2 > tyy: ICMP echo request, id 12661, seq 9, length 64
16:11:30.657507 IP tyy > 172.18.0.2: ICMP echo reply, id 12661, seq 9, length 64
16:11:30.658005 ARP, Request who-has 100.100.2.136 tell tyy, length 28
16:11:31.681503 ARP, Request who-has 100.100.2.136 tell tyy, length 28
16:11:31.681562 IP 172.18.0.2 > tyy: ICMP echo request, id 12661, seq 10, length 64
16:11:31.681595 IP tyy > 172.18.0.2: ICMP echo reply, id 12661, seq 10, length 64

Linux Bridge

Bridge是用来桥接的网络设备,可以把它理解成功交换机,可以连接不同的网络设备,当请求到达Bridge设备时,可以通过报文中的Mac地址进行广播或者转发。在容器环境中可以连接Namespace中网络设备和宿主机上的网络。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 安装brctl工具
[root@tyy ~]# yum install bridge-utils
# 配置ns veth
[root@tyy ~]# ip netns list
[root@tyy ~]# ip netns add ns1
[root@tyy ~]# ip link add veth0 type veth peer name veth1
[root@tyy ~]# ip link set veth1 netns ns1
# 创建网桥
[root@tyy ~]# brctl addbr br0
[root@tyy ~]# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.000000000000 no
# 将eth0和veth0挂载到br0上,如上图所示,veth1是挂载到ns1中的,veth0挂载到br0上,eth0也挂载到br0上,这样整条网络路线就搭上了,剩下的就是配置ip和route了.
[root@tyy ~]# brctl addif br0 eth0
[root@tyy ~]# brctl addif br0 veth0
#

Linux路由表

Linux路由表是Linux内核的一个模块,通过定义路由表来决定某个Namespace的网络流向。

1
2
3
4
5
6
7
8
9
# 启动虚拟设备
[root@tyy ~]# ip linke set veth0 up
[root@tyy ~]# ip linke set br0 up
# 设置ns中IP地址
[root@tyy ~]# ip netns exec ns1 ifconfig veth1 172.18.0.2/24 up
# 设置ns1上网络路由, default代表0.0.0.0/0,代表ns1中的所有网络数据都由veth1走
[root@tyy ~]# ip netns exec ns1 route add default dev veth1
# 宿主机上所有172.18.0.0/24网段请求路由到br0上
[root@tyy ~]# route add -net 172.18.0.0/24 dev br0

实例

1
2
3
4
# 查看eth0地址
[root@tyy ~]# ifconfig eth0
# ping eth0IP, 这里IP填自己的。
[root@tyy ~]# ip netns exec ns1 ping eth0IP

Linux iptables

iptables是Linux内核中netfilter的工具,用来管理数据包的流动和转发。iptables定义了一套链式处理的结构,再网络报文传输的各个阶段使用不同策略对报文加工、传送、丢弃。在容器环境中常使用两种策略MASQUERADE和DNAT,用于和宿主机外部的网络通信。

MASQUERADE

MASQUERADE是用来发送数据的网卡上的IP替换源IP。(可以将请求包中的源地址转换成一个网络设备的地址)

DNAT

DNAT就是指数据包从网卡发送出去的时候,修改数据包中的目的IP。

SNAT

SNAT是指在数据包从网卡发送出去的时候,把数据包中的源地址部分替换为指定的IP。

实例

1
2
3
4
5
6
7
# 打开ip转发
[root@tyy ~]# sysctl -w net.ipv4.conf.all.forwarding=1
net.ipv4.conf.allforwarding = 1
# ns1中发出的报文的源地址转换成eth0的地址
[root@tyy ~]# iptables -t nat -A POSTROUTING -s 172.18.0.0/24 -o eth0 -j MASQUERADE
# 将宿主机上80端口的tcp请求转发到ns1中172.18.0.2:80这个地址上.
[root@tyy ~]# iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.2:80