邢森:Java、Python码农,运营“写程序的康德”自媒体。现就职于上海电信信息网络部任职架构师,主要负责网络相关产品的研发工作。
前言
上一章介绍了GNS3的使用以及OVN系统的架构,搭建了实验环境,阐述了OVN各个进程的用途、彼此之间的关系,以及产生的日志(OVN实战一之GNS3操作指南及OVN入门,http://www.sdnlab.com/19765.html)。本章主要介绍我们实验的拓扑结构,然后实现拓扑中的相应功能。
一、实验环境
1.1 拓扑结构
上面拓扑中有四个“虚拟机(VM)”,分别属于两个广播域(二层交换机,SW),SW1和SW2通过R1连接起来。本章先实现SW1和SW2两个网络。
为了验证实验网络的Overlay功能(VXLAN封包、解包),这里故意把VM1和VM2分配到不同的物理机上,物理上的分布如下:
VM1、VM3运行在ovn-node2上;VM2、VM4运行在ovn-node3上。
1.2 准备虚拟机
笔者的实验资源有限,所以就不通过Hypervisor来创建虚拟机而是通过Linux network namespace模拟虚拟机。
Linux network namespace是Linux从2.6.24开始提供的一种“隔离技术”,它允许一个Linux内核可以拥有多个隔离的网络空间(独立的ARP表、路由表、IP地址、接口)。通过下面命令分别在ovn-node2、ovn-node3上创建VM1和VM2:
在ovn-node2上执行创建虚拟机VM1:
1 2 3 4 5 | sudo ip netns add vm1 sudo ip link add vm1-eth0 type veth peer name veth-vm1 sudo ip link set veth-vm1 up sudo ip link set vm1-eth0 netns vm1 |
为了便于测试此处使用固定MAC地址
1 2 3 4 5 6 7 8 9 10 11 | sudo ip netns exec vm1 ip link set vm1-eth0 addres 00:00:00:00:00:01
sudo ip netns exec vm1 ip link set vm1-eth0 up sudo ovs-vsctl add-port br-int veth-vm1 sudo ip netns add vm3 sudo ip link add vm3-eth0 type veth peer name veth-vm3 sudo ip link set veth-vm3 up sudo ip link set vm3-eth0 netns vm3 sudo ip netns exec vm3 ip link set vm3-eth0 address 00:00:00:00:00:03
sudo ip netns exec vm3 ip link set vm3-eth0 up sudo ovs-vsctl add-port br-int veth-vm3 |
在ovn-node3上执行创建虚拟机VM2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | sudo ip netns add vm2 sudo ip link add vm2-eth0 type veth peer name veth-vm2 sudo ip link set veth-vm2 up sudo ip link set vm2-eth0 netns vm2 sudo ip netns exec vm2 ifconfig vm2-eth0 hw ether 00:00:00:00:00:02
sudo ip netns exec vm2 ip link set vm2-eth0 up sudo ovs-vsctl add-port br-int veth-vm2 sudo ip netns add vm4 sudo ip link add vm4-eth0 type veth peer name veth-vm4 sudo ip link set veth-vm4 up sudo ip link set vm4-eth0 netns vm4 sudo ip netns exec vm4 ip link set vm4-eth0 address 00:00:00:00:00:04
sudo ip netns exec vm4 ip link set vm4-eth0 up sudo ovs-vsctl add-port br-int veth-vm4 |
我们用VETH来模拟模拟虚拟机的网卡,这是Linux提供的一种虚拟网络设备,它通常成对出现,送到一端请求发送的数据总是从另一端以请求接受的形式出现。我们一般把VETH的一端用于连接网桥,一段放入到net namespace中作为网卡。用同样的命令上创建VM3、VM4。
1.3创建SW1搭建拓扑
OVN的所有操作都在ovn-central节点完成,当需要操作网络拓扑中的“虚拟机”的时候我们才会用到ovn-host节点。OVN提供了两个命令行工具叫ovn-sbctl、ovn-nbctl,根据名字不难想到,ovn-sbctl是用来操作SB的;ovn-nbctl是用来操作NB的。逻辑交换机、逻辑路由器是放在NB中的所以和我们经常打交道的是ovn-nbctl。
在ovn-node1上执行:
1 2 3 4 5 | sudo ovn-nbctl ls-add sw1 sudo ovn-nbctl lsp-add sw1 sw1-vm1 sudo ovn-nbctl lsp-set-addresses sw1-vm1 "00:00:00:00:00:01 192.168.100.10" sudo ovn-nbctl lsp-add sw1 sw1-vm2 sudo ovn-nbctl lsp-set-addresses sw1-vm2 "00:00:00:00:00:02 192.168.100.20"
|
ls-add命令用于添加逻辑交换机,lsp-add命令用于为逻辑交换机添加端口,在OVN中每个逻辑交换机都有一个唯一的命名。lsp-set-addresses为逻辑交换机端口配置MAC地址和IP地址,这一步骤是不可省略的,OVN会根据这两个信息生成流表
上述命令通过ovn-nbctl工具在NB中添加了一个逻辑交换机、两个逻辑交换机端口;ovn-northd进程会“发现”这个改变,然后读取NB中的数据把它转换成流表写入到SB数据库中(可以通过ovn-sbctl list Logical_Flow查看相关流表)。但是此时流表并没有下发到ovn-host中,需要通过下面命令建立逻辑交换机端口和OVS端口(ovn-host上的OVS)的关联。
在ovn-node2上执行
1 | sudo ovs-vsctl set Interface veth-vm1 external_ids:iface-id=sw1-vm1 |
设置IP地址,必须和lsp-set-addresses 中的一致
1 | sudo ip netns exec vm1 ip addr add 192.168.100.10/24 dev vm1-eth0 |
在ovn-node3上执行
1 2 | sudo ovs-vsctl set Interface veth-vm2 external_ids:iface-id=sw1-vm2 sudo ip netns exec vm2 ip addr add 192.168.100.20/24 dev vm2-eth0
|
二、验证结果
在node2上执行ping命令发送ICMP数据包;在GNS3中右击ovn-node2到SW1之间的链路选择“start capture”,GNS3会自动启动Wireshark抓取这段链路上的数据包。
ping命令正常执行,说明vm1和vm2之间可以互相通讯
Wireshark抓取的数据包显示,网络中传送的数据包是VxLAN封装后的Overlay数据包(VNI是1)
注意,Wireshark并没有抓到vm1和vm2之间的ARP数据包,这是OVN的一个特性叫“ARP Responder”,它的实现原理在调试部分说明。
2.1 调试
OVS提供了一个叫ofproto/trace的流表分析工具,用于分析数据包在流表中如何被“处理”。
在ovn-node2上执行
1 | sudo ovs-appctl ofproto/trace br-int in_port=3,icmp,nw_src=192.168.100.10,nw_dst=192.168.100.20,dl_dst=00:00:00:00:00:02,dl_src=00:00:00:00:00:01 |
in_port指定数据包从哪个端口进来的,可以通过sudo ovs-ofctl dump-ports-desc br-int
查看veth-vm1对应的port编号,在我的环境中它是3。
icmp指定了数据包类型
nw_src源IP地址
nw_dst是目标IP地址
dl_src是源MAC地址
dl_dst是目标MAC地址。
完整的输出太长,这里截取最后一部分,数据包最终被设置上tun_id=1从port2中发送出去。
通过sudo ovs-dpctl show
可以查看DataPath和Port的对应关系,port 2对应的是vxlan_sys_xxxx,它是一种特殊的ovs port用于VXLAN的封包。
下面看一下ARP数据包是如何处理的
ovn-node2上执行
1 | sudo ovs-appctl ofproto/trace br-int in_port=3,arp,arp_tpa=192.168.100.20,arp_op=1,dl_src=00:00:00:00:00:01 |
arp_tpa是目标IP地址
arp_op是ARP数据包类型,1表示request数据包,2表示reply数据包
ARP数据并没有被发送到到ovn-node3而直接在ovn-node2就终结了,流表自动构造了一个ARP Reply数据包回送到来源端口,这个特性就叫ARP Responder。
创建SW2
SW2的创建过程和SW1很像,此处直接罗列命令:
在ovn-node1上执行
1 2 3 4 5 | sudo ovn-nbctl ls-add sw2 sudo ovn-nbctl lsp-add sw2 sw2-vm3
sudo ovn-nbctl lsp-set-addresses sw2-vm3 "00:00:00:00:00:03 192.168.200.30" sudo ovn-nbctl lsp-add sw2 sw2-vm4 sudo ovn-nbctl lsp-set-addresses sw2-vm4 "00:00:00:00:00:04 192.168.200.40" |
在ovn-node2上执行
1 2 | sudo ovs-vsctl set Interface veth-vm3 external_ids:iface-id=sw2-vm3 sudo ip netns exec vm3 ip addr add 192.168.200.30/24 dev vm3-eth0 |
在ovn-node3上执行
1 2 | sudo ovs-vsctl set Interface veth-vm4 external_ids:iface-id=sw2-vm4
sudo ip netns exec vm4 ip addr add 192.168.200.40/24 dev vm4-eth0 |
验证WWW服务
这组环境用于验证TCP服务是否能正常工作,笔者在vm4上启动一个WWW服务,在vm3上通过curl访问。
在ovn-node3上执行
1 | sudo ip netns exec vm4 python -m SimpleHTTPServer 8080 |
在ovn-node2上执行
1 | sudo ip netns exec vm3 curl http://192.168.200.40:8080 |
执行结果如下图所示,说明WWW服务正常工作
创建R1
在ovn-node1上执行
1 | sudo ovn-nbctl lr-add r1
|
此处的IP地址相当于路由表,输入格式是CIRD
1 2 3 4 5 6 7 8 9 10 11 | sudo ovn-nbctl lrp-add r1 r1-sw1 00:00:00:00:10:00 192.168.100.1/24 sudo ovn-nbctl lsp-add sw1 sw1-r1 sudo ovn-nbctl lsp-set-type sw1-r1 router sudo ovn-nbctl lsp-set-addresses sw1-r1 00:00:00:00:10:00 sudo ovn-nbctl lsp-set-options sw1-r1 router-port=r1-sw1
sudo ovn-nbctl lrp-add r1 r1-sw2 00:00:00:00:20:00 192.168.200.1/24 sudo ovn-nbctl lsp-add sw2 sw2-r1 sudo ovn-nbctl lsp-set-type sw2-r1 router sudo ovn-nbctl lsp-set-addresses sw2-r1 00:00:00:00:20:00 sudo ovn-nbctl lsp-set-options sw2-r1 router-port=r1-sw2
|
由于Linux namespace没有默认网关,所以需要为vm1、vm2、vm3、vm4配置默认网关
ovn-node2
1 2 | sudo ip netns exec vm1 ip route add default via 192.168.100.1 sudo ip netns exec vm3 ip route add default via 192.168.200.1 |
ovn-node3
1 2 | sudo ip netns exec vm2 ip route add default via 192.168.100.1 sudo ip netns exec vm4 ip route add default via 192.168.200.1 |
通过vm1访问vm4的WWW服务,说明R1已经生效。
参考资料
OVS每个字段的说明,流表的语法规则 http://openvswitch.org/support/dist-docs/ovs-ofctl.8.html
NB数据库结构 http://openvswitch.org/support/dist-docs/ovn-nb.5.html
SB数据库结构 http://openvswitch.org/support/dist-docs/ovn-sb.5.html