本文是博主投稿SDNLAB的文章。原文链接:http://www.sdnlab.com/19157.html
OVN是由开发出OVS的那群出色的程序员们的另一个优秀的作品。这个网络虚拟化项目从2015初宣告启动,到不久前才发布第一个正式版本OVN 2.6 。在这篇文章中,我会配置一个简单示例:在三个主机之间配置一个layer-2 overlay网络。
首先讲一下OVN工作机制中的2种角色:
OVN Central ——目前只能有一台主机承担这个角色。该主机将成为和外部资源(比如云管理平台)集成的API中心节点。中心节点运行着OVN北向数据库和OVN南向数据库。OVN北向数据库,用于描述上层的逻辑网络组件,比如逻辑交换机/逻辑端口。南向数据库,其将北向数据库的逻辑网络数据格式转换为物理网络数据格式并进行存储。
OVN Host ——所有提供虚拟机或虚拟网络的节点。OVN Host运行着 "chassis controller",它上连OVN南向数据库并作为其记录的物理网络信息授权来源,下接OVS并成为其openflow控制器。
本次实验中使用了3台Ubuntu 16.04主机
OVN实验拓扑: 3台Ubuntu 16.04主机都连接到同一个管理网络 10.127.0.0/25
主机的角色和IP地址分配如下:
ubuntu1 10.127.0.2 –作为OVN Central
ubuntu2 10.127.0.3 –作为 OVN Host
ubuntu3 10.127.0.4 –作为OVN Host
物理网络拓扑图如下:
为了方便测试,将会创建OVS内部接口并在网络命名空间(namespace)中使用沙盒技术来模拟虚拟机。命名空间能保证我们的OVN overlay网络与实验网络完全隔离。
2016年9月28日社区发布了 Open vSwitch 2.6版本,可以从 这里下载。下载包中的Ubuntu的指导手册 INSTALL.Debian.md 非常不错。下面是按照这个指导手册进行实验后的总结:
首先为三台主机编译出相应的版本的OVS(注意ubuntu内核版本)
更新和安装依赖包:
apt-get update
apt-get -y install build-essential fakeroot
安装编译工具包:
apt-get -y install graphviz autoconf automake bzip2 debhelper dh-autoreconf libssl-dev libtool openssl
apt-get -y install procps python-all python-twisted-conch python-zopeinterface python-six
进行编译:
cd openvswitch-2.6.0
dpkg-checkbuilddeps
`DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary`
生成的OVS的.deb文件路径为当前路径的上一层目录。
下面会编译openvswitch-datapath内核模块
安装datapath源:
cd ..
apt-get -y install module-assistant
dpkg -i openvswitch-datapath-source_2.6.0-1_all.deb
使用 module-assistant编译内核模块
m-a prepare
m-a build openvswitch-datapath
复制生成的deb包。你们重复这个实验时注意,版本号跟这里的输出的可能存在不同。
cp /usr/src/openvswitch-datapath-module-*.deb ./
把下面的这些包传到三台Ubuntu主机上:
openvswitch-datapath-module-*.deb
openvswitch-common_2.6.0-1_amd64.deb
openvswitch-switch_2.6.0-1_amd64.deb
ovn-common_2.6.0-1_amd64.deb
ovn-central_2.6.0-1_amd64.deb
ovn-host_2.6.0-1_amd64.deb
在ubuntu1上安装 OVS/OVN和依赖包:
apt-get update
apt-get -y install python-six python2.7
dpkg -i openvswitch-datapath-module-*.deb
dpkg -i openvswitch-common_2.6.0-1_amd64.deb openvswitch-switch_2.6.0-1_amd64.deb
dpkg -i ovn-common_2.6.0-1_amd64.deb ovn-central_2.6.0-1_amd64.deb ovn-host_2.6.0-1_amd64.deb
在ubuntu2、ubuntu3上安装 OVS/OVN 和依赖包:
apt-get update
apt-get -y install python-six python2.7
dpkg -i openvswitch-datapath-module-*.deb
dpkg -i openvswitch-common_2.6.0-1_amd64.deb openvswitch-switch_2.6.0-1_amd64.deb
dpkg -i ovn-common_2.6.0-1_amd64.deb ovn-host_2.6.0-1_amd64.deb
这些包安装完成后,去ubuntu1上检查下ovsdb-server进程是否监听TCP 6641,6642端口。6641端口用于监听OVN北向数据库,6642端口用于监听OVN南向数据库。下面是我执行netstat的输出结果:
root@ubuntu1:~# netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:6641 0.0.0.0:* LISTEN 1798/ovsdb-server
tcp 0 0 0.0.0.0:6642 0.0.0.0:* LISTEN 1806/ovsdb-server
较新版本的OVN可能没有上述输出结果,则需要手工执行以下命令:ovn-nbctl set-connection ptcp:6641:10.127.0.2
ovn-sbctl set-connection ptcp:6642:10.127.0.2
如果 ovsdb-server没有使用 6641/6642那么需要通过运行启动脚本来启动这些进程。启动脚本路径为/etc/init.d/openvswitch-switch和 /etc/init.d/ovn-central。
OVS的网桥要连接到一个集成化网桥后才能够被OVN管理。通常我们给这个集成化网桥命名为"br-int"(其实可以任意命名)。首先检查环境中是否存在这个网桥,不存在的话进行就创建。
在ubuntu2、ubuntu3上:
ovs-vsctl list-br
如果看不到"br-int"网桥,那么需要手工创建。注意:所有运行虚拟机的节点都要存在"br-int"网桥。
ovs-vsctl add-br br-int -- set Bridge br-int fail-mode=secure
ovs-vsctl list-br
"fail-mode=secure"是一个安全特性,其让网桥丢掉任何流量。这里用这个参数是因为我们不想在OVN控制器启用前使用网络。
接下来将ubuntu2/ubuntu3上的chassis控制器连接到ubuntu 1上的中央控制器
ubuntu2:
ovs-vsctl set open . external-ids:ovn-remote=tcp:10.127.0.2:6642
ovs-vsctl set open . external-ids:ovn-encap-type=geneve
ovs-vsctl set open . external-ids:ovn-encap-ip=10.127.0.3
ubuntu3:
ovs-vsctl set open . external-ids:ovn-remote=tcp:10.127.0.2:6642
ovs-vsctl set open . external-ids:ovn-encap-type=geneve
ovs-vsctl set open . external-ids:ovn-encap-ip=10.127.0.4
这些命令将触发ubuntu2/ubuntu3上的OVN chassis控制器发起一个到ubuntu 1上的中央控制器的连接。我们同时指定了overlay网络封装数据平面流量的协议为 geneve 协议。
在ubuntu2/ubuntu3使用netstat校验连接是否建立:
root@ubuntu3:~# netstat -antp | grep 10.127.0.2
tcp 0 0 10.127.0.4:39256 10.127.0.2:6642 ESTABLISHED 3072/ovn-controller
下图是本次实验的OVN逻辑网络拓扑图。
在ubuntu1定义一台逻辑交换机和相关的逻辑端口:
# 创建logical switch
ovn-nbctl ls-add ls1
# 创建 logical port
ovn-nbctl lsp-add ls1 ls1-vm1
ovn-nbctl lsp-set-addresses ls1-vm1 02:ac:10:ff:00:11
ovn-nbctl lsp-set-port-security ls1-vm1 02:ac:10:ff:00:11
# 创建 logical port
ovn-nbctl lsp-add ls1 ls1-vm2
ovn-nbctl lsp-set-addresses ls1-vm2 02:ac:10:ff:00:22
ovn-nbctl lsp-set-port-security ls1-vm2 02:ac:10:ff:00:22
ovn-nbctl show
注意,虚拟端口的名称是唯一的,不能重复。虚拟端口同时也会生成一个很长的UUID。本文使用更加人性化的端口名称来代表这些端口。我们同时定义了这些虚拟端口的mac地址。在端口安全实验(逻辑端口只允许特定的源mac地址数据包通过)将用到这些mac地址。
接下来创建连接到逻辑交换机的"伪虚拟机"。上文已经提到,我们会使用OVS内部端口和网络命名空间来模拟虚拟机。我们会给这台逻辑交换机分配172.16.255.0/24网络。
ubuntu2:
ip netns add vm1
ovs-vsctl add-port br-int vm1 -- set interface vm1 type=internal
ip link set vm1 netns vm1
ip netns exec vm1 ip link set vm1 address 02:ac:10:ff:00:11
ip netns exec vm1 ip addr add 172.16.255.11/24 dev vm1
ip netns exec vm1 ip link set vm1 up
ovs-vsctl set Interface vm1 external_ids:iface-id=ls1-vm1
ip netns exec vm1 ip addr show
ubuntu3:
ip netns add vm2
ovs-vsctl add-port br-int vm2 -- set interface vm2 type=internal
ip link set vm2 netns vm2
ip netns exec vm2 ip link set vm2 address 02:ac:10:ff:00:22
ip netns exec vm2 ip addr add 172.16.255.22/24 dev vm2
ip netns exec vm2 ip link set vm2 up
ovs-vsctl set Interface vm2 external_ids:iface-id=ls1-vm2
ip netns exec vm2 ip addr show
如果你从没接触过命名空间或者OVS,也许会对这些命令很困惑。
其实我们进行了如下几步操作:
给"伪虚拟机"创建了网络命名空间,
再给它添加一个OVS内部端口,
再把端口添加到命名空间,
在命名空间内部使用netns exec命令配置 IP地址
最后创建一个OVS接口,并给这个接口指定一个external_id。(这个ID是之前创建的逻辑接口的名称或UUID)
最后一步执行完成后,OVS就会通知OVN有逻辑端口上线了。然后,OVN向下游主机的本地chassis控制器发送指令,同时 OVN也会将网络流量传递给上游的OVS。
注意,我已明确地给这些接口设置了与OVN逻辑交换机中相同的mac地址。这非常重要。如果mac地址没有映射正确,逻辑网络就不会正常工作。请记住,我在这里没有使用常规流程。正常情况下,你不会更改VM的MAC地址,而是将现有的/已知的mac地址传递入OVN / OVS。我为了演示方便才手动设置IP/mac地址。
在 ubuntu1,我们使用ovn-sbctl验证逻辑网络配置 :
root@ubuntu1:~# ovn-sbctl show
Chassis "239f2c28-90ff-468f-a701-655585c630bf"
hostname: "ubuntu3"
Encap geneve
ip: "10.127.0.4"
options: {csum="true"}
Port_Binding "ls1-vm2"
Chassis "517d558e-158a-4cb2-8870-283e9d39685e"
hostname: "ubuntu2"
Encap geneve
ip: "10.127.0.3"
options: {csum="true"}
Port_Binding "ls1-vm1"
重点检查每个OVN主机的端口绑定是否正常。
为了测试网络连通性,我们只需从vm1的命名空间发起ping:
root@ubuntu2:~# ip netns exec vm1 ping 172.16.255.22
PING 172.16.255.22 (172.16.255.22) 56(84) bytes of data.
64 bytes from 172.16.255.22: icmp_seq=1 ttl=64 time=1.60 ms
64 bytes from 172.16.255.22: icmp_seq=2 ttl=64 time=0.638 ms
64 bytes from 172.16.255.22: icmp_seq=3 ttl=64 time=0.344 ms
让我们添加一个第三方"虚拟机",然后在主机之间迁移它。首先,在ubuntu1上使用ovn-nbctl定义其逻辑端口:
ovn-nbctl lsp-add ls1 ls1-vm3
ovn-nbctl lsp-set-addresses ls1-vm3 02:ac:10:ff:00:33
ovn-nbctl lsp-set-port-security ls1-vm3 02:ac:10:ff:00:33
ovn-nbctl show
然后在ubuntu2上给这台虚拟机创建接口:
ip netns add vm3
ovs-vsctl add-port br-int vm3 -- set interface vm3 type=internal
ip link set vm3 netns vm3
ip netns exec vm3 ip link set vm3 address 02:ac:10:ff:00:33
ip netns exec vm3 ip addr add 172.16.255.33/24 dev vm3
ip netns exec vm3 ip link set vm3 up
ovs-vsctl set Interface vm3 external_ids:iface-id=ls1-vm3
ip netns exec vm3 ip addr show
从vm3测试网络:
root@ubuntu2:~# ip netns exec vm3 ping 172.16.255.22
PING 172.16.255.22 (172.16.255.22) 56(84) bytes of data.
64 bytes from 172.16.255.22: icmp_seq=1 ttl=64 time=2.04 ms
64 bytes from 172.16.255.22: icmp_seq=2 ttl=64 time=0.337 ms
64 bytes from 172.16.255.22: icmp_seq=3 ttl=64 time=0.536 ms
注意ubuntu1上的OVN南向数据库配置。我们看到ubuntu2有2个注册的端口绑定。
root@ubuntu1:~# ovn-sbctl show
Chassis "239f2c28-90ff-468f-a701-655585c630bf"
hostname: "ubuntu3"
Encap geneve
ip: "10.127.0.4"
options: {csum="true"}
Port_Binding "ls1-vm2"
Chassis "517d558e-158a-4cb2-8870-283e9d39685e"
hostname: "ubuntu2"
Encap geneve
ip: "10.127.0.3"
options: {csum="true"}
Port_Binding "ls1-vm3"
Port_Binding "ls1-vm1"
为了模拟vm3的迁移,我们将删除ubuntu2上的"vm3"命名空间,删除其在br-int上的端口,然后在ubuntu3上重新进行配置。
ubuntu2:
ip netns del vm3
ovs-vsctl --if-exists --with-iface del-port br-int vm3
ovs-vsctl list-ports br-int
ubuntu3:
ip netns add vm3
ovs-vsctl add-port br-int vm3 -- set interface vm3 type=internal
ip link set vm3 netns vm3
ip netns exec vm3 ip link set vm3 address 02:ac:10:ff:00:33
ip netns exec vm3 ip addr add 172.16.255.33/24 dev vm3
ip netns exec vm3 ip link set vm3 up
ovs-vsctl set Interface vm3 external_ids:iface-id=ls1-vm3
测试网络连通性:
root@ubuntu3:~# ip netns exec vm3 ping 172.16.255.11
PING 172.16.255.11 (172.16.255.11) 56(84) bytes of data.
64 bytes from 172.16.255.11: icmp_seq=1 ttl=64 time=1.44 ms
64 bytes from 172.16.255.11: icmp_seq=2 ttl=64 time=0.407 ms
64 bytes from 172.16.255.11: icmp_seq=3 ttl=64 time=0.395 ms
同样,请注意ubuntu1上的OVN南向数据库配置。我们看到端口绑定已经改变。
root@ubuntu1:~# ovn-sbctl show
Chassis "239f2c28-90ff-468f-a701-655585c630bf"
hostname: "ubuntu3"
Encap geneve
ip: "10.127.0.4"
options: {csum="true"}
Port_Binding "ls1-vm2"
Port_Binding "ls1-vm3"
Chassis "517d558e-158a-4cb2-8870-283e9d39685e"
hostname: "ubuntu2"
Encap geneve
ip: "10.127.0.3"
options: {csum="true"}
Port_Binding "ls1-vm1"
为了让环境用于后面的其他实验,我们在退出前需要清理环境。
ubuntu1:
#删除逻辑交换机及其端口
ovn-nbctl ls-del ls1
ubuntu2:
# 删除 vm1
ip netns del vm1
ovs-vsctl --if-exists --with-iface del-port br-int vm1
ubuntu3:
# delete vm2 和 vm3
ip netns del vm2
ovs-vsctl --if-exists --with-iface del-port br-int vm2
ip netns del vm3
ovs-vsctl --if-exists --with-iface del-port br-int vm3
如您所见,使用OVN创建二层overlay网络相对简单。在下一篇文章中,我们将通过引入OVN逻辑路由器来构建一个OVN基本的三层网络。