openvswitch vlan - hanyong/note GitHub Wiki
操作环境: ubuntu 14.04 .
任务: 在宿主机上创建一个大局域网 192.168.0.0/16
, 设置 vlan 将其划分为若干个小局域网, 如 192.168.2.0/24
.
- 安装文档参考: https://github.com/openvswitch/ovs/blob/master/INSTALL.md
- Isolating VM Traffic Using VLANs
- How to Use Open vSwitch with Libvirt
- libvirt 配置文档: https://libvirt.org/formatdomain.html#elementVlanTag
简单说, 在 ubuntu 上直接安装 openvswitch-switch
即可:
sudo aptitude install openvswitch-switch
安装完成后会出现一个 ovs-system
, 这个是 ovs 自己用的, 不用管它.
系统启动时 openvswitch-switch
服务会自动启动并创建我们添加的 vswitch .
使用 ovs-vsctl
操作 vswitch, 类似 brctl
.
首先我们创建一个 vswitch:
sudo ovs-vsctl add-br ovs0
使用 ip link
可看到我们创建的 vswitch:
$ ip -d link show
... ...
4: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default
link/ether 06:55:a9:87:45:c0 brd ff:ff:ff:ff:ff:ff promiscuity 1
openvswitch
5: ovs0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/ether a6:d6:ae:84:27:4b brd ff:ff:ff:ff:ff:ff promiscuity 1
openvswitch
使用 ovs-vsctl show
可看到更加详细的信息:
$ sudo ovs-vsctl show
b99c5bde-570e-4192-bd61-c78a974a77e3
Bridge "ovs0"
Port "ovs0"
Interface "ovs0"
type: internal
ovs_version: "2.0.2"
接下来我们要设置局域网访问外网入口和网关. 有两种方式:
- 使用宿主机作为外网入口和网关,
ovs0
设置为网关地址. - 新建一个 vm 作为网关, 但还是要使用宿主机作为外网入口, 网关使用宿主机上的
ovs0
作为外网路由.
为了减少对宿主机的污染, 我们采用方案2.
网关分配 IP 地址 192.168.1.1
, 外网路由 ovs0
分配 IP 地址 192.168.1.2
.
因为外网看不到局域网 IP 地址, 局域网访问外网还要设置 NAT 转换.
宿主机上 /etc/network/interfaces
添加如下配置:
auto ovs0
iface ovs0 inet static
address 192.168.1.2/24
up ip route add 192.168.0.0/16 via 192.168.1.1 dev ovs0
up iptables -t nat -A POSTROUTING -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j MASQUERADE
down ip route del 192.168.0.0/16
down iptables -t nat -D POSTROUTING -s 192.168.0.0/16 ! -d 192.168.0.0/16 -j MASQUERADE
dns-nameserver 192.168.1.1
注意, 现在我们还没有设置 vlan, 姑且称之为公有网络, ovs0 和网关都在公有网络上.
整个大局域网的网段是 192.168.0.0/16
, 但稍后我们将设置的 vlan 子网和公有网络并不在一个局域网,
因此我们给 ovs0
指定了一个公有网络内较小的网段 192.168.1.0/24
.
而大局域网网段 192.168.0.0/16
通过网关 192.168.1.1
访问.
同时也使用局域网网关作局域网 DNS 解析.
宿主机要做路由, 还要在 /etc/sysctl.conf
设置 net.ipv4.ip_forward=1
, 执行 sudo sysctl -p
使其立即生效.
创建虚拟机 node1n1 作为大局域网网关. ovs0 和网关都在公有网络上, 不需要设置 vlan. libvirt 网卡配置如下:
<interface type='bridge'>
<source bridge='ovs0'/>
<virtualport type='openvswitch'/>
<model type='virtio'/>
</interface>
/etc/network/interfaces
主网卡 eth0 配置如下:
auto eth0
iface eth0 inet static
address 192.168.1.1/16
gateway 192.168.1.2
dns-nameserver 192.168.1.2
网关所在网段为大局域网网段 192.168.0.0/16
,
使用宿主机 ovs0 IP 192.168.1.2
作为默认路由,
宿主机还配置了 DNS 解析, 同样使用 ovs0 IP 访问.
查看路由表如下:
hanyong@node1n1:~$ ip route
default via 192.168.1.2 dev eth0
192.168.0.0/16 dev eth0 proto kernel scope link src 192.168.1.1
hanyong@node1n1:~$ netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.1.2 0.0.0.0 UG 0 0 0 eth0
192.168.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
安装 dnsmasq
:
sudo aptitude install dnsmasq
添加 dhcp 配置 /etc/dnsmasq.d/dhcp.conf
:
dhcp-range=192.168.1.51,192.168.1.99,255.255.255.0,12h
domain=local
domain-needed
expand-hosts
类似 ovs0, 设置 dhcp 分配的客户端 IP 地址限制在较小的公有网络段 192.168.1.0/24
.
dnsmasq 会从 /etc/hosts
文件读 hostname 和 IP 对应表反馈给 DNS 查询,
修改 /etc/hosts
文件将 127.0.1.1 node1n1
修改为 192.168.1.1 node1n1
.
重启 dnsmasq:
sudo service dnsmasq restart
网关也要设置 sysctl net.ipv4.ip_forward=1
.
公有网络添加一台虚拟机, 其能使用 dhcp 自动完成网络设置.
vlan 网关即要通过带 vlan id tag 的包与同一 vlan 内其他机器通信, 又要通过公有网络上网, 因此我们不对 vlan 网关的网卡做 vlan id 过滤. libvirt 网卡配置与大局域网网关 (公有网络) 网卡配置相同.
创建虚拟机 node2n1 作为 vlan id=2 的网关, 分配 IP 地址 192.168.2.1
.
安装 vlan
包使其能自动识别 /etc/network/interfaces
中的 vlan 配置:
sudo aptitude install vlan
/etc/network/interfaces
文件配置如下:
auto eth0
iface eth0 inet static
pre-up ip route add 192.168.1.1/32 dev eth0
address 192.168.2.1/32
gateway 192.168.1.1
dns-nameserver 192.168.1.1
auto eth0.2
iface eth0.2 inet static
address 192.168.2.1/24
vlan 网关同时处于公有网络和 vlan 子网两个局域网中,
为了简化 IP 分配和容易记忆,
我们给网关在两个子网中分配了一样的 IP 地址 192.168.2.1
,
但只希望其通过 eth0.2
访问 vlan 中的 IP 段 192.168.2.1/24
,
不希望访问大局域网的任何 IP 段, 因此 eth0 配置了 address 192.168.2.1/32
.
但需要通过大局域网网关 192.168.1.1
上网,
ip route add 192.168.1.1/32 dev eth0
表示通过 eth0 与 192.168.1.1/32
同一个局域网内直连.
配置好网络后查看路由表如下:
hanyong@node2n1:~$ ip route
default via 192.168.1.1 dev eth0
192.168.1.1 dev eth0 scope link
192.168.2.0/24 dev eth0.2 proto kernel scope link src 192.168.2.1
hanyong@node2n1:~$ netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0
192.168.1.1 0.0.0.0 255.255.255.255 UH 0 0 0 eth0
192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0.2
vlan 网关已经可以正常上网.
vlan 网关同样需要设置 sysctl net.ipv4.ip_forward=1
,
及安装 dnsmasq 为 vlan 机器提供 DHCP 和 DNS 解析服务.
/etc/dnsmasq.d/dhcp.conf
配置如下:
#bind-interfaces
except-interface=eth0
#no-dhcp-interface=eth0
dhcp-range=192.168.2.51,192.168.2.99,12h
domain=local
domain-needed
expand-hosts
注意: vlan 网关与大局域网网关在同一个局域网, 即前面所说的公有网络, 一个局域网内只能有一个 DHCP 服务, 公有网络的 DHCP 服务由大局域网网关提供, 所以每个 vlan 网关的 DHCP 服务都应该在公有网络上禁止掉, 只服务于 vlan 内部. 为来验证这一点, 大局域网网关停掉 dnsmasq 服务器后, 公有网络机器应无法访问 DHCP 服务.
按同样的办法, 我们可以再创建一个 vlan id=3 的 vlan 网关 node3n1.
添加一台 vlan id=2 的机器 node2n2, libvirt 网卡配置如下:
<interface type='bridge'>
<source bridge='ovs0'/>
<virtualport type='openvswitch'/>
<vlan>
<tag id="2"/>
</vlan>
<model type='virtio'/>
</interface>
/etc/network/interfaces
配置为自动 dhcp:
auto eth0
iface eth0 inet dhcp
机器启动后查看网络配置ok:
hanyong@node2n2:~$ ip route
default via 192.168.2.1 dev eth0
192.168.2.0/24 dev eth0 proto kernel scope link src 192.168.2.99
hanyong@node2n2:~$ netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.2.1 0.0.0.0 UG 0 0 0 eth0
192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
hanyong@node2n2:~$ cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 192.168.2.1
search local
但是只能访问 vlan 网络, 无法访问外网, 大局域网网关也 ping 不通:
hanyong@node2n2:~$ ping -c 1 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.263 ms
--- 192.168.2.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.263/0.263/0.263/0.000 ms
hanyong@node2n2:~$ ping -c 1 baidu.com
PING baidu.com (180.149.132.47) 56(84) bytes of data.
--- baidu.com ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
hanyong@node2n2:~$ ping -c 1 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
--- 192.168.1.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
这是因为 vlan 与大局域网不在一个局域网, vlan 的设计正是如此!
为了使 vlan 能够通过大局域网网关上网, 有两个办法:
- vlan 网关设置 NAT 转换
- 外部网络(及公有网络)应通过 vlan 网关路由到 vlan 网段
为了使整个大局域网能联通, 同时避免两次 NAT, 我们使用方案2. 大局域网的网关 node1n1 添加如下路由规则:
ip route add 192.168.2.0/24 via 192.168.2.1
添加后查看路由规则如下:
hanyong@node1n1:~$ ip route
default via 192.168.1.2 dev eth0
192.168.0.0/16 dev eth0 proto kernel scope link src 192.168.1.1
192.168.2.0/24 via 192.168.2.1 dev eth0
hanyong@node1n1:~$ netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.1.2 0.0.0.0 UG 0 0 0 eth0
192.168.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
192.168.2.0 192.168.2.1 255.255.255.0 UG 0 0 0 eth0
同样的, 在大局域网网关上为其他 vlan 也添加路由.
vlan id=2 的机器 node2n2, vlan id=3 的机器 node3n2, 大局域网网关添加 vlan 路由后, 不同 vlan 之间的机器就能互相访问.
hanyong@node3n2:~$ ip route
default via 192.168.3.1 dev eth0
192.168.3.0/24 dev eth0 proto kernel scope link src 192.168.3.76
hanyong@node2n2:~$ ping 192.168.3.76
PING 192.168.3.76 (192.168.3.76) 56(84) bytes of data.
64 bytes from 192.168.3.76: icmp_seq=1 ttl=61 time=1.42 ms
64 bytes from 192.168.3.76: icmp_seq=2 ttl=61 time=0.452 ms
64 bytes from 192.168.3.76: icmp_seq=3 ttl=61 time=0.422 ms
64 bytes from 192.168.3.76: icmp_seq=4 ttl=61 time=0.426 ms
^C
--- 192.168.3.76 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.422/0.682/1.429/0.431 ms
注意, 因为 vlan 间的 DNS 没有打通, 只能通过 IP 访问.
实际上, vlan 内的机器通过公有网络访问外网, 那么外网和公有网络就一定有办法访问到 vlan 内的机器.
要做到 vlan 内(或整个大局域网)机器的安全隔离, 可以在 vlan 网关(或整个大局域网网关)添加安全过滤规则. 可按 IP 或按端口过滤, 如禁止外网访问 vlan 内端口小于 10000 的端口.
如不希望 vlan id=2 的机器与大局域网内其他机器互通, 可在 vlan 网关 node2n1 配置禁止对目标地址为大局域网 IP 段的包进行转发. 配置如下:
iptables -A FORWARD -d 192.168.2.0/24 -j ACCEPT
iptables -A FORWARD -d 192.168.0.0/16 -j DROP
注意:
-
如果直接限制整个大局域网的 IP 段, vlan 访问外部网络返回数据包也会被限制, vlan 将无法访问外网, 相当于 vlan 网关掐断外网. 要保留 vlan 访问外网的能力, 需要将本 vlan IP 段添加白名单.
-
我们只限制了目标 IP 段, 没有限制来源 IP 段. 对 TCP 等协议需要双向通信, 禁止了一个方向的通信, 就无法建立连接和通信. 但注意 UDP 等不需要反馈的单向通信协议还能在单个方向上通信. 仅限制其他网段目标地址, 则其他网段还能发 UDP 包过来. 修改为来源地址限定可能更好, 或者双向都限定. vlan 到外网, 外网到 vlan, 双向都要添加白名单. 外网到 vlan 可添加端口限制.
最后再说一下, vlan 之间能互通, 是因为我们在大局域网网关设置了路由, 以便共用大局域网网关访问外网, 正如上一节提到的方案2. 要使 vlan 完全隔离, 我们只要选择方案1, 在 vlan 网关再做一次 NAT, 大局域网网关去掉对应路由, 即可完全独立. 外网或其他 vlan 机器只能间接访问到大局域网网关或其他 vlan 网关, 他们即无法控制大局域网网关的行为(路由规则), 也无法设置间接连接的 vlan 网关为路由. 两次 NAT 后, 外部无法直连 NAT 的点, 因而可以做到完全隔离. 这时多个 vlan 还可以复用同一个 IP 段.