VLAN 和策略路由

VLAN(虚拟局域网)通过控制分派出入局域网的数据包到正确的出入端口,实现对不同设备进行逻辑分组管理。一个 VLAN 相当于广播域,它能将广播控制在一个 VLAN 内部。而不同 VLAN 之间或 VLAN 与 LAN / WAN 的数据通信必须通过网络层完成。VLAN 可以降低局域网内大量数据流通时,因无用数据包过多导致雍塞的问题,以及提升局域网的安全性。

对 Linux 来说,通常通过 vconfig 或 ip link add 来配置 vlan,创建虚拟 VLAN 网络接口。如

ip link add link eth0 name vlan100 type vlan id 100
ip link change vlan100 up
ip addr add 10.10.100.201/24 dev vlan100

创建了一个 VLAN 接口 vlan100,对应 VLAN 号是 100,并配置了 IP 10.10.100.201。此时,同一个 VLAN 中的机器相互间用 VLAN 的 IP 都可以访问。但是如果两个机器各自位于不同的 VLAN,则相互之间是无法通过 IP 访问,也无法 ping 通。

Linux 的路由通常情况下是按 IP 包的目的地址查询路由表的。如果 IP 包的来源和目的位于不同的 VLAN,或者一个位于 VLAN ,另一个是普通的链路,就会对应不同的网络接口。响应包根据路由表查询得到的网络接口,由于响应包的目的地址不在 VLAN 内,就不会从 VLAN 的接口返回,通常会路由到默认路由。而默认路由上并没有配置相应IP,因此无法通过该接口发生 IP 包,由此导致无法访问。

既然是由于这个原因,那想要解决就有两种途径。一是允许在这种情况下从不同的接口中发生 IP 包,再通过默认网关转发。可以通过更改系统 Linux 系统配置实现:

echo 1 >/proc/sys/net/ipv4/conf/all/accept_local
echo 2 >/proc/sys/net/ipv4/conf/all/rp_filter

配置后,相互就可以 ping 通了,通过 IP 也可以访问了。

另一种途径就是配置路由规则,让响应包从 VLAN 接口返回,再通过 VLAN 网关转发。也就是策略路由。
首先为 VLAN 定义一个路由表

echo "100 vlan100" >/etc/iproute2/rt_tables

这里 100 是路由表的 ID,vlan100 是路由表的名字。都可以随便起,只要不和现有 ID 和名字重复即可。这儿就用和 VLAN ID、VLAN 接口名相同的数字和名字。

然后为路由表设置默认网关

ip route add default via 10.10.100.1 dev vlan100 table vlan100

这里的 10.10.100.1 就是该 VLAN 的默认网关。dev vlan100 是 VLAN 接口名 table vlan100 是路由表名。

然后为 VLAN 对应的 IP 段添加源地址路由规则,使用刚定义的路由表。

ip rule add from 10.10.100.0/24 table vlan100

这样源地址为 VLAN 100 的包就会根据规则从 VLAN 接口转往 VLAN 的默认网关了。

配置完成后,同样可以实现互通。那这两种方式有什么区别呢?通过抓包看看。在一台不在 VLAN 中的机器持续 ping IP,在 VLAN 的机器上用 tcpdump 抓包。从实际网络接口上抓 ping 的 icmp 包,加上 -e 输出以太网头。
使用系统配置的结果如下:

# tcpdump -e -n icmp -i eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
10:49:50.640326 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 559, length 64
10:49:50.640351 1a:42:cb:eb:bb:e9 > 90:b1:1c:42:9e:18, ethertype IPv4 (0x0800), length 98: 10.10.100.201 > 10.186.21.101: ICMP echo reply, id 20246, seq 559, length 64
10:49:51.641921 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 560, length 64
10:49:51.641942 1a:42:cb:eb:bb:e9 > 90:b1:1c:42:9e:18, ethertype IPv4 (0x0800), length 98: 10.10.100.201 > 10.186.21.101: ICMP echo reply, id 20246, seq 560, length 64
10:49:52.643386 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 561, length 64

使用策略路由的结果如下:

# tcpdump -e -n icmp -i eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
10:36:13.098805 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, 10.186.21.101 > 10.10.100.201: ICMP echo request, id 32277, seq 1695, length 64
10:36:13.098830 1a:42:cb:eb:bb:e9 > 90:b1:1c:42:9e:18, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, 10.10.100.201 > 10.186.21.101: ICMP echo reply, id 32277, seq 1695, length 64
10:36:14.100301 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, 10.186.21.101 > 10.10.100.201: ICMP echo request, id 32277, seq 1696, length 64
10:36:14.100323 1a:42:cb:eb:bb:e9 > 90:b1:1c:42:9e:18, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4, 10.10.100.201 > 10.186.21.101: ICMP echo reply, id 32277, seq 1696, length 64

可以看出,使用系统配置的方式由于没有从 VLAN 接口发出包,因此发出的包虽然 IP 头是对的,但是丢失了 VLAN TAG 数据。

以上环境是在 xen 虚拟化环境中实现的。在宿主机上的 VLAN 相应设备上抓包也可以看出差异:
使用系统配置:

# tcpdump -n -e -i xapi0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on xapi0, link-type EN10MB (Ethernet), capture size 65535 bytes
10:55:40.426937 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype IPv4 (0x0800), length 98: 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 908, length 64
10:55:41.428269 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype IPv4 (0x0800), length 98: 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 909, length 64
10:55:42.429593 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype IPv4 (0x0800), length 98: 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 910, length 64
10:55:43.430682 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype IPv4 (0x0800), length 98: 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 910, length 64

使用策略路由:

# tcpdump -n -e -i xapi0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on xapi0, link-type EN10MB (Ethernet), capture size 65535 bytes
10:55:09.392195 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype IPv4 (0x0800), length 98: 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 877, length 64
10:55:09.392586 1a:42:cb:eb:bb:e9 > 90:b1:1c:42:9e:18, ethertype IPv4 (0x0800), length 98: 10.10.100.201 > 10.186.21.101: ICMP echo reply, id 20246, seq 877, length 64
10:55:10.393333 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype IPv4 (0x0800), length 98: 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 878, length 64
10:55:10.393646 1a:42:cb:eb:bb:e9 > 90:b1:1c:42:9e:18, ethertype IPv4 (0x0800), length 98: 10.10.100.201 > 10.186.21.101: ICMP echo reply, id 20246, seq 878, length 64
10:55:10.394210 90:b1:1c:42:9e:18 > 1a:42:cb:eb:bb:e9, ethertype IPv4 (0x0800), length 98: 10.186.21.101 > 10.10.100.201: ICMP echo request, id 20246, seq 879, length 64
10:55:10.394433 1a:42:cb:eb:bb:e9 > 90:b1:1c:42:9e:18, ethertype IPv4 (0x0800), length 98: 10.10.100.201 > 10.186.21.101: ICMP echo reply, id 20246, seq 879, length 64

可以看到,只有请求的包通过了 VLAN,而响应包并没有出现在 VLAN 中。

使用系统配置方式的副作用是,造成了实际上返回包并不属于该 VLAN。这样的话,在更严格的网络配置下可能无法使用,同时也失去了 VLAN 在流量隔离、流量监控、流量限制方面的意义。因此,正确的方式还是要通过策略路由实现。

Leave a Reply

Your email address will not be published. Required fields are marked *