OpenvSwitch,简称OVS是一个虚拟交换软件,主要用于虚拟机VM环境,作为一个虚拟交换机,支持Xen/XenServer, KVM, and VirtualBox多种虚拟化技术。 在虚拟化平台上,OVS 可以为动态变化的端点提供 2 层交换功能,很好的控制虚拟网络中的访问策略、网络隔离、流量监控等等。
OVS 遵循 Apache 2.0 许可证, 能同时支持多种标准的管理接口和协议。OVS 也提供了对 OpenFlow 协议的支持,用户可以使用任何支持 OpenFlow 协议的控制器对 OVS 进行远程管理控制。
在这种某一台机器的虚拟化的环境中,一个虚拟交换机(vswitch)主要有两个作用:传递虚拟机VM之间的流量,以及实现VM和外界网络的通信。
The bulk of the code is written in platform-independent C and is easily ported to other environments. The current release of Open vSwitch supports the following features: • Standard 802.1Q VLAN model with trunk and access ports • NIC bonding with or without LACP on upstream switch • NetFlow, sFlow(R), and mirroring for increased visibility • QoS (Quality of Service) configuration, plus policing • Geneve, GRE, VXLAN, STT, and LISP tunneling • 802.1ag connectivity fault management • OpenFlow 1.0 plus numerous extensions • Transactional configuration database with C and Python bindings • High-performance forwarding using a Linux kernel module
By default all files are installed under /usr/local. Open vSwitch also expects to find its database in /usr/local/etc/openvswitch by default. If you want to install all files into, e.g., /usr and /var instead of /usr/local and /usr/local/var and expect to use /etc/openvswitch as the default database directory, add options as shown here:
./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc make && make installOpenFlow 是用于管理交换机流表的协议,ovs-ofctl 则是 OVS 提供的命令行工具。在没有配置 OpenFlow 控制器的模式下,用户可以使用 ovs-ofctl 命令通过 OpenFlow 协议去连接 OVS,创建、修改或删除 OVS 中的流表项,并对 OVS 的运行状况进行动态监控。 OpenFlow 的匹配流程,如下图所示(来源于网络)
flow被定义为某个特定的网络流量。例如:一个tcp连接就是一个flow,或者从某个ip地址发出来的数据包,都可以认为是一个flow。支持openflow协议的交换机应该包含一个或多个流表,流表中的条目包含:数据包头的信息、匹配成功之后要执行的指令和统计信息。 当数据包进入ovs后,会将数据包和流表中的流表项进行匹配,如果发现了匹配的流表项,则执行该流表项中的指令集。相反,如果数据包在流表中没有发现任何匹配,ovs会通过控制通道把数据包发送到openflow控制器中。
在ovs中,流表项作为ovs-ofctl的参数,采用如下的格式:字段=值。如果有多个字段,可以用逗号或者空格分开。一些常用的字段列举如下:
对于 add−flow,add−flows 和 mod−flows 这三个命令,还需要指定要执行的动作:actions=[target][,target…] 一个流规则中可能有多个动作,按照指定的先后顺序执行。 常见的操作有:
除了使用“ping”、“tcpdump”和“iperf” 等 Linux 命令以外,我们也可以使用 OVS 提供的 ovs-appctl ofproto/trace 工具来测试 OVS 对数据包的转发状况。ovs-appctl ofproto/trace 可以用来生成测试用的模拟数据包,并一步步的展示 OVS 对数据包的流处理过程。
#设置端口p1 vlan=101 ovs-vsctl set port p1 tag=101现在由于端口 p0 和 p1 属于不同的 VLAN,它们之间无法进行数据交换。我们使用 ovs-appctl ofproto/trace 生成一个从端口 p0 发送到端口 p1 的数据包,这个数据包不包含任何 VLAN tag,并观察 OVS 的处理过程。
ovs-appctl ofproto/trace ovs-switch in_port=100,dl_src=1a:63:2e:ad:b9:c4,dl_dst=1a:50:8c:91:b3:07 -generate Flow: in_port=100,vlan_tci=0x0000,dl_src=1a:63:2e:ad:b9:c4,dl_dst=1a:50:8c:91:b3:07,dl_type=0x0000 bridge("ovs-switch") -------------------- 0. in_port=100, priority 1 mod_nw_src:192.168.100.2 NORMAL -> learned that 1a:63:2e:ad:b9:c4 is on port p0 in VLAN 0 -> no learned MAC for destination, flooding Final flow: unchanged Megaflow: recirc_id=0,eth,in_port=100,vlan_tci=0x0000/0x1fff,dl_src=1a:63:2e:ad:b9:c4,dl_dst=1a:50:8c:91:b3:07,dl_type=0x0000 Datapath actions: 2,4说明: 在第一行输出中,“Flow:”之后的字段描述了输入的流的信息。由于我们没有指定太多信息,所以多数字段 (例如 dl_type 和 vlan_tci)被 OVS 设置为空值。 在第二行的输出中,“Rule:” 之后的字段描述了匹配成功的流表项。 在第三行的输出中,“OpenFlow actions”之后的字段描述了实际执行的操作。 最后一段以”Final flow”开始的字段是整个处理过程的总结,“Datapath actions: 2,4”代表数据包被发送到 datapath 的 2 和 4 号端口。
#对于从端口 p0 进入交换机的数据包, #如果它不包含任何 VLAN tag,则自动为它添加 VLAN tag 101 ovs-ofctl add-flow ovs-switch "priority=3,in_port=100,dl_vlan=0xffff,actions=mod_vlan_vid:101,normal" #查看信息 #发现数据包进入端口 p0 之后, 会被加上 VLAN tag101, 同时转发到端口 p1 上 ovs-appctl ofproto/trace ovs-switch in_port=100,dl_src=1a:63:2e:ad:b9:c4,dl_dst=1a:50:8c:91:b3:07 -generate Flow: in_port=100,vlan_tci=0x0000,dl_src=1a:63:2e:ad:b9:c4,dl_dst=1a:50:8c:91:b3:07,dl_type=0x0000 bridge("ovs-switch") -------------------- 0. in_port=100,vlan_tci=0x0000, priority 3 mod_vlan_vid:101 NORMAL -> learned that 1a:63:2e:ad:b9:c4 is on port p0 in VLAN 101 -> no learned MAC for destination, flooding Final flow: in_port=100,dl_vlan=101,dl_vlan_pcp=0,vlan_tci1=0x0000,dl_src=1a:63:2e:ad:b9:c4,dl_dst=1a:50:8c:91:b3:07,dl_type=0x0000 Megaflow: recirc_id=0,eth,in_port=100,vlan_tci=0x0000,dl_src=1a:63:2e:ad:b9:c4,dl_dst=1a:50:8c:91:b3:07,dl_type=0x0000 Datapath actions: push_vlan(vid=101,pcp=0),2,pop_vlan,1,push_vlan(vid=101,pcp=0),4 #反过来从端口 p1 发送数据包,由于 p1 现在是带有 VLAN tag 101 的 Access 类型的端口, #所以数据包进入端口 p1 之后,会被 OVS 添加 VLAN tag 101 并发送到端口 p0 ovs-appctl ofproto/trace ovs-switch in_port=101,dl_dst=1a:63:2e:ad:b9:c4,dl_src=1a:50:8c:91:b3:07 -generate Flow: in_port=101,vlan_tci=0x0000,dl_src=1a:50:8c:91:b3:07,dl_dst=1a:63:2e:ad:b9:c4,dl_type=0x0000 bridge("ovs-switch") -------------------- 0. priority 0 NORMAL -> learned that 1a:50:8c:91:b3:07 is on port p1 in VLAN 101 -> forwarding to learned port Final flow: unchanged Megaflow: recirc_id=0,eth,in_port=101,vlan_tci=0x0000/0x1fff,dl_src=1a:50:8c:91:b3:07,dl_dst=1a:63:2e:ad:b9:c4,dl_type=0x0000 Datapath actions: push_vlan(vid=101,pcp=0),3端口Port与物理交换机的端口概念类似,Port是OVS Bridge上创建的一个虚拟端口,每个Port都隶属于一个Bridge。Port有以下几种类型:
把物理网卡(eth1)attach到ovs上,ovs会生成一个同名的port(eth1)处理这块网卡进出的数据。此时端口类型为Normal。
ovs-vsctl add-port br-ex eth1 ovs-vsctl show #显示信息如下: Bridge br-ex Controller "tcp:127.0.0.1:6633" is_connected: true fail_mode: secure Port phy-br-ex Interface phy-br-ex type: patch options: {peer=int-br-ex} Port "eth1" Interface "eth1" Port br-ex Interface br-ex type: internal注意:attach到ovs上的网卡设备(物理网卡、虚拟网卡)不支持分配IP地址,因此若之前eth1有ip地址,attach之后ip地址失效。
Internal类型是ovs内部创建的虚拟网卡接口,每创建一个port,ovs会自动创建一个同名接口(interface)挂载到新创建的port上。
ovs-vsctl add-br br0 ovs-vsctl add-port br0 port0 -- set Interface port0 type=internal ovs-vsctl show显示信息如下:
ad3594eb-ebf6-4255-916f-c737b652d7bf Bridge "br0" Port "br0" Interface "br0" type: internal Port "port0" Interface "port0" type: internal Bridge ovs-bridge-test Port ovs-bridge-test Interface ovs-bridge-test type: internal ovs_version: "2.8.90"可以看到有两个port。当ovs创建一个新网桥时,默认会创建一个与网桥同名的internal port(如:br0)。在ovs中,只有“internal”类型的设备才支持配置IP地址信息,因此我们可以为br0和port0配置ip地址。
ip addr add 100.2.97.10/24 dev br0 ip link set dev br0 up ip route add default via 100.2.97.1 dev br0上面两种Port类型区别在于,Internal类型会自动创建接口(Interface),而Normal类型是把主机中已有的网卡接口添加到OVS中
当主机中有多个ovs网桥时,可以使用patch port把两个网桥连接起来。Patch port总是成对存在,分别连接在两个网桥上,从一个patch port收到的数据包会被发送到另一个patch port上,类似于linux中的veth。使用patch连接的两个网桥跟一个网桥没什么区别,openstack neutron中使用到了patch port。比如连接br-int和br-ext的patch port。
Bridge br-int Port int-br-ex Interface int-br-ex type: patch options: {peer=phy-br-ex} Bridge br-ex Port phy-br-ex Interface phy-br-ex type: patch options: {peer=int-br-ex} root@ubuntu:/# ovs-vsctl add-br br0 root@ubuntu:/# ovs-vsctl add-br br1 root@ubuntu:/# ovs-vsctl \ > -- add-port br0 patch0 -- set interface patch0 type=patch options:peer=patch1 \ > -- add-port br1 patch1 -- set interface patch1 type=patch options:peer=patch0 root@ubuntu:/# ovs-vsctl show ad3594eb-ebf6-4255-916f-c737b652d7bf Bridge "br1" Port "br1" Interface "br1" type: internal Port "patch1" Interface "patch1" type: patch options: {peer="patch0"} Bridge "br0" Port "br0" Interface "br0" type: internal Port "patch0" Interface "patch0" type: patch options: {peer="patch1"} Bridge ovs-bridge-test Port ovs-bridge-test Interface ovs-bridge-test type: internal ovs_version: "2.8.90"连接两个网桥不止上面一种方法,linux中支持创建Veth设备对,我们可以首先创建一对Veth设备对,然后把这两个Veth分别添加到两个网桥上,其效果跟OVS中创建Patch Port一样,只是性能会有差别.
Open vSwitch中PATCH类型的端口有如下定义:“A pair of virtual devices that act as a patch cable”(一根虚拟电缆),同时在OpenvSwitch官方FAQ可以找到PATCH端口的用途“If you still want to connect two bridges, you can use a pair of patch ports”(用于连接两个网桥)。 简单化,patch port成对,可以看作是一根虚拟电缆,用来连接两个网桥,如下图:
#创建网桥br1、br2 ovs-vsctl add-br br1 ovs-vsctl add-br br2 #创建内部端口 ovs-vsctl add-port br1 tap1 -- set Interface tap1 type=internal ovs-vsctl add-port br2 tap2 -- set Interface tap2 type=internal #配置namespace ip netns add ns1 ip netns add ns2 ip link set dev tap1 netns ns1 ip link set dev tap2 netns ns2 ip netns exec ns1 ip addr add 100.2.96.11/24 dev tap1 ip netns exec ns1 ip link set tap1 up ip netns exec ns1 ip link set lo up ip netns exec ns2 ip addr add 100.2.96.12/24 dev tap2 ip netns exec ns2 ip link set tap2 up ip netns exec ns2 ip link set lo up # patch port ovs-vsctl add-port br1 patch-ovs-1 -- set Interface patch-ovs-1 type=patch -- set Interface patch-ovs-1 options:peer=patch-ovs-2 ovs-vsctl add-port br2 patch-ovs-2 -- set Interface patch-ovs-2 type=patch -- set Interface patch-ovs-2 options:peer=patch-ovs-1 #test ip netns exec ns1 ping 100.2.96.12 ip netns exec ns2 ping 100.2.96.11显示信息如下
root@ubuntu:/home/sunld# ovs-vsctl show ad3594eb-ebf6-4255-916f-c737b652d7bf Bridge "br2" Port "tap2" Interface "tap2" type: internal Port "br2" Interface "br2" type: internal Port "patch-ovs-2" Interface "patch-ovs-2" type: patch options: {peer="patch-ovs-1"} Bridge "br1" Port "tap1" Interface "tap1" type: internal Port "patch-ovs-1" Interface "patch-ovs-1" type: patch options: {peer="patch-ovs-2"} Port "br1" Interface "br1" type: internal Bridge ovs-bridge-test Port ovs-bridge-test Interface ovs-bridge-test type: internal ovs_version: "2.8.90"ovs官网 ovs安装 What Is Open vSwitch? OVS - 简介 ovs命令基础 基于 Open vSwitch 的 OpenFlow 实践