00 Ovs预备知识
Open vSwitch是一个高质量的、多层虚拟交换机,使用开源Apache2.0许可协议,由Nicira Networks开发,主要实现代码为可移植的C代码。它的目的是让大规模网络自动化可以通过编程扩展,同时仍然支持标准的管理接口和协议(例如NetFlow, sFlow, SPAN, RSPAN, CLI, LACP, 802.1ag)。此外,它被设计位支持跨越多个物理服务器的分布式环境,类似于VMware的vNetwork分布式vswitch或Cisco Nexus 1000 V。Open vSwitch支持多种linux 虚拟化技术,包括Xen/XenServer, KVM和irtualBox。当前最新代码包主要包括以下模块和特性:
- ovs-vswitchd 主要模块,实现switch的daemon,包括一个支持流交换的Linux内核模块;
- ovsdb-server 轻量级数据库服务器,提供ovs-vswitchd获取配置信息;
- ovs-brcompatd 让ovs-vswitch替换Linuxbridge,包括获取bridge ioctls的Linux内核模块;
- ovs-dpctl 用来配置switch内核模块;
一些Scripts and specs 辅助OVS安装在Citrix XenServer上,作为默认switch;
- ovs-vsctl 查询和更新ovs-vswitchd的配置;
- ovs-appctl 发送命令消息,运行相关daemon;
- ovsdbmonitor GUI工具,可以远程获取OVS数据库和OpenFlow的流表。
此外,OVS也提供了支持OpenFlow的特性实现,包括
- ovs-openflowd:一个简单的OpenFlow交换机;
- ovs-controller:一个简单的OpenFlow控制器;
- ovs-ofctl 查询和控制OpenFlow交换机和控制器;
- ovs-pki :OpenFlow交换机创建和管理公钥框架;
- ovs-tcpundump:tcpdump的补丁,解析OpenFlow的消息;
内核模块实现了多个“数据路径”(类似于网桥),每个都可以有多个“vports”(类似于桥内的端口)。每个数据路径也通过关联一下流表(flow table)来设置操作,而这些流表中的流都是用户空间在报文头和元数据的基础上映射的关键信息,一般的操作都是将数据包转发到另一个vport。当一个数据包到达一个vport,内核模块所做的处理是提取其流的关键信息并在流表中查找这些关键信息。当有一个匹配的流时它执行对应的操作。如果没有匹配,它会将数据包送到用户空间的处理队列中(作为处理的一部分,用户空间可能会设置一个流用于以后碰到相同类型的数据包可以在内核中执行操作)。
在基于Linux内核的系统上,应用最广泛的还是系统自带的虚拟交换机Linux Bridge,它是一个单纯的基于MAC地址学习的二层交换机,简单高效,但同时缺乏一些高级特性,比如OpenFlow,VLAN tag,QOS,ACL,Flow等,而且在隧道协议支持上,Linux Bridge只支持vxlan,OVS支持gre/vxlan/IPsec等,这也决定了OVS更适用于实现SDN技术
OVS支持以下features
- 支持NetFlow, IPFIX, sFlow, SPAN/RSPAN等流量监控协议
- 精细的ACL和QoS策略
- 可以使用OpenFlow和OVSDB协议进行集中控制
- Port bonding,LACP,tunneling(vxlan/gre/Ipsec)
- 适用于Xen,KVM,VirtualBox等hypervisors
- 支持标准的802.1Q VLAN协议
- 基于VM interface的流量管理策略
- 支持组播功能
- flow-caching engine(datapath模块)
先看下OVS整体架构,用户空间主要组件有数据库服务ovsdb-server和守护进程ovs-vswitchd。kernel中是datapath内核模块。最上面的Controller表示OpenFlow控制器,控制器与OVS是通过OpenFlow协议进行连接,控制器不一定位于OVS主机上,下面分别介绍图中各组件

ovs-vswitchd守护进程是OVS的核心部件,它和datapath内核模块一起实现OVS基于流的数据交换。作为核心组件,它使用openflow协议与上层OpenFlow控制器通信,使用OVSDB协议与ovsdb-server通信,使用netlink和datapath内核模块通信。ovs-vswitchd在启动时会读取ovsdb-server中配置信息,然后配置内核中的datapaths和所有OVS switches,当ovsdb中的配置信息改变时(例如使用ovs-vsctl工具),ovs-vswitchd也会自动更新其配置以保持与数据库同步
# ps -ef |grep ovs-vs
root 22176 22175 0 Jan17 ? 00:16:56 ovs-vswitchd unix:/var/run/openvswitch/db.sock -vconsole:emer -vsyslog:err -vfile:info --mlockall --no-chdir --log-file=/var/log/openvswitch/ovs-vswitchd.log --pidfile=/var/run/openvswitch/ovs-vswitchd.pid --detach --monitor
ovs-vswitchd需要加载datapath内核模块才能正常运行。它会自动配置datapath flows,因此我们不必再使用ovs-dpctl去手动操作datapath,但ovs-dpctl仍可用于调试场合
在OVS中,ovs-vswitchd从OpenFlow控制器获取流表规则,然后把从datapath中收到的数据包在流表中进行匹配,找到匹配的flows并把所需应用的actions返回给datapath,同时作为处理的一部分,ovs-vswitchd会在datapath中设置一条datapath flows用于后续相同类型的数据包可以直接在内核中执行动作,此datapath flows相当于OpenFlow flows的缓存。对于datapath来说,其并不知道用户空间OpenFlow的存在,datapath内核模块信息如下
# modinfo openvswitch
filename: /lib/modules/3.10.0-327.el7.x86_64/kernel/net/openvswitch/openvswitch.ko
license: GPL
description: Open vSwitch switching datapath
rhelversion: 7.2
srcversion: F75F2B83324DCC665887FD5
depends: libcrc32c
intree: Y
...
ovsdb-server是OVS轻量级的数据库服务,用于整个OVS的配置信息,包括接口/交换内容/VLAN等,OVS主进程ovs-vswitchd根据数据库中的配置信息工作,下面是ovsdb-server进程详细信息
ps -ef |grep ovsdb-server
root 22166 22165 0 Jan17 ? 00:02:32 ovsdb-server /etc/openvswitch/conf.db -vconsole:emer -vsyslog:err -vfile:info --remote=punix:/var/run/openvswitch/db.sock --private-key=db:Open_vSwitch,SSL,private_key --certificate=db:Open_vSwitch,SSL,certificate --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert --no-chdir --log-file=/var/log/openvswitch/ovsdb-server.log --pidfile=/var/run/openvswitch/ovsdb-server.pid --detach --monitor
/etc/openvswitch/conf.db是数据库文件存放位置,文件形式存储保证了服务器重启不会影响其配置信息,ovsdb-server需要文件才能启动,可以使用ovsdb-tool create命令创建并初始化此数据库文件
--remote=punix:/var/run/openvswitch/db.sock 实现了一个Unix sockets连接,OVS主进程ovs-vswitchd或其它命令工具(ovsdb-client)通过此socket连接管理ovsdb
/var/log/openvswitch/ovsdb-server.log是日志记录
OpenFlow是开源的用于管理交换机流表的协议,OpenFlow在OVS中的地位可以参考上面架构图,它是Controller和ovs-vswitched间的通信协议。需要注意的是,OpenFlow是一个独立的完整的流表协议,不依赖于OVS,OVS只是支持OpenFlow协议,有了支持,我们可以使用OpenFlow控制器来管理OVS中的流表,OpenFlow不仅仅支持虚拟交换机,某些硬件交换机也支持OpenFlow协议
OVS常用作SDN交换机(OpenFlow交换机),其中控制数据转发策略的就是OpenFlow flow。OpenStack Neutron中实现了一个OpenFlow控制器用于向OVS下发OpenFlow flows控制虚拟机间的访问或隔离。本文讨论的默认是作为SDN交换机场景下
OpenFlow flow的流表项存放于用户空间主进程ovs-vswitchd中,OVS除了连接OpenFlow控制器获取这种flow,文章后面会提到的命令行工具ovs-ofctl工具也可以手动管理OVS中的OpenFlow flow,可以查看man ovs-ofctl了解
在OVS中,OpenFlow flow是最重要的一种flow, 然而还有其它几种flows存在,文章下面OVS概念部分会提到
Controller指OpenFlow控制器。OpenFlow控制器可以通过OpenFlow协议连接到任何支持OpenFlow的交换机,比如OVS。控制器通过向交换机下发流表规则来控制数据流向。除了可以通过OpenFlow控制器配置OVS中flows,也可以使用OVS提供的ovs-ofctl命令通过OpenFlow协议去连接OVS,从而配置flows,命令也能够对OVS的运行状况进行动态监控。
下面讨论场景是OVS作为一个OpenFlow交换机
datapath是一个Linux内核模块,它负责执行数据交换。关于datapath,The Design and Implementation of Open vSwitch中有描述
The datapath module in the kernel receives the packets first, from a physical NIC or a VM’s virtual NIC. Either ovs-vswitchd has instructed the datapath how to handle packets of this type, or it has not. In the former case, the datapath module simply follows the instructions, called actions, given by ovs-vswitchd, which list physical ports or tunnels on which to transmit the packet. Actions may also specify packet modifications, packet sampling, or instructions to drop the packet. In the other case, where the datapath has not been told what to do with the packet, it delivers it to ovs-vswitchd. In userspace, ovs-vswitchd determines how the packet should be handled, then it passes the packet back to the datapath with the desired handling. Usually, ovs-vswitchd also tells the datapath to cache the actions, for handling similar future packets.
为了说明datapath,来看一张更详细的架构图,图中的大部分组件上面都有提到

用户空间ovs-vswitchd和内核模块datapath决定了数据包的转发,首先,datapath内核模块收到进入数据包(物理网卡或虚拟网卡),然后查找其缓存(datapath flows),当有一个匹配的flow时它执行对应的操作,否则datapath会把该数据包送入用户空间由ovs-vswitchd负责在其OpenFlow flows中查询(图1中的First Packet),ovs-vswitchd查询后把匹配的actions返回给datapath并设置一条datapath flows到datapath中,这样后续进入的同类型的数据包(图1中的Subsequent Packets)因为缓存匹配会被datapath直接处理,不用再次进入用户空间。
datapath专注于数据交换,它不需要知道OpenFlow的存在。与OpenFlow打交道的是ovs-vswitchd,ovs-vswitchd存储所有Flow规则供datapath查询或缓存.
虽然有ovs-dpctl管理工具的存在,但我们没必要去手动管理datapath,这是用户空间ovs-vswitchd的工作
使用OpenStack neutron+vxlan部署模式下网络节点OVS网桥作为例子
ovs-vsctl show
e44abab7-2f65-4efd-ab52-36e92d9f0200
Manager "ptcp:6640:127.0.0.1"
is_connected: true
Bridge br-ext
Controller "tcp:127.0.0.1:6633"
is_connected: true
fail_mode: secure
Port br-ext
Interface br-ext
type: internal
Port "eth1"
Interface "eth1"
Port phy-br-ext
Interface phy-br-ext
type: patch
options: {peer=int-br-ext}
Bridge br-tun
Controller "tcp:127.0.0.1:6633"
is_connected: true
fail_mode: secure
Port br-tun
Interface br-tun
type: internal
Port patch-int
Interface patch-int
type: patch
options: {peer=patch-tun}
Port "vxlan-080058ca"
Interface "vxlan-080058ca"
type: vxlan
options: {df_default="true", in_key=flow, local_ip="8.0.88.201", out_key=flow, remote_ip="8.0.88.202"}
Bridge br-int
Controller "tcp:127.0.0.1:6633"
is_connected: true
fail_mode: secure
Port "qr-11591618-c4"
tag: 3
Interface "qr-11591618-c4"
type: internal
Port patch-tun
Interface patch-tun
type: patch
options: {peer=patch-int}
Port int-br-ext
Interface int-br-ext
type: patch
options: {peer=phy-br-ext}
Bridge代表一个以太网交换机(Switch),一个主机中可以创建一个或者多个Bridge。Bridge的功能是根据一定规则,把从端口收到的数据包转发到另一个或多个端口,上面例子中有三个Bridge,br-tun,br-int,br-ext
添加一个网桥br0
ovs-vsctl add-br br0
网桥的fail-mode设置
- standalone:该模式下,没有运行controller的情况下,OVS会自动调整为普通交换机模式,像物理交换机一样,此时可能会有环路产生的问题。如果有controller的情况,OVS会自动变成openflow交换机
- secure: 该模式下,无论有没有controller,OVS都会作为openflow交换机运行,也就是所有网桥上的端口,等待controller或者用户添加flow到OVS来进行通信。
端口Port与物理交换机的端口概念类似,Port是OVS Bridge上创建的一个虚拟端口,每个Port都隶属于一个Bridge。Port有以下几种类型
可以把操作系统中已有的网卡(物理网卡em1/eth0,或虚拟机的虚拟网卡tapxxx)挂载到ovs上,ovs会生成一个同名Port处理这块网卡进出的数据包。此时端口类型为Normal。
如下,主机中有一块物理网卡eth1,把其挂载到OVS网桥br-ext上,OVS会自动创建同名Port eth1。
ovs-vsctl add-port br-ext eth1 #Bridge br-ext中出现port “eth1”
有一点要注意的是,挂载到OVS上的网卡设备不支持分配IP地址(当网卡加入到网桥之后,网卡是交换机上的一个端口,交换机作为二层设备,其端口是不可能有IP地址的),因此若之前eth1配置有IP地址,挂载到OVS之后IP地址将不可访问。这里的网卡设备不只包括物理网卡,也包括主机上创建的虚拟网卡。(原网卡IP可以设置到与ovs桥同名的interanl类型的port在系统上的网卡)
如果是操作系统上的网卡设备(比如veth pair设备、物理网卡、网卡VLAN子接口等)加入ovs桥,这种port的类型即为Normal类型的port。Normal类型的Port在操作系统上依然可见,但是不能为其配置IP。(如果要实现物理网卡上配置IP还有连入OVS桥,可以考虑使用veth pair设备)
Internal类型是OVS内部创建的虚拟网卡接口,每创建一个Port,OVS会自动创建一个同名接口(Interface)挂载到新创建的Port上。接口的概念下面会提到。
下面创建一个网桥br0,并创建一个internal类型的Port p0
ovs-vsctl add-br br0
ovs-vsctl add-port br0 p0 -- set Interface p0 type=internal #此时p0这个设备会出现在操作系统上,可以通过ip a查看到
查看结果
#查看网桥br0
ovs-vsctl show br0
Bridge "br0"
fail_mode:secure
Port "p0"
Interface "p0"
type:internal
Port "br0"
Interface "br0"
type:internal
可以看到有两个Port。当ovs创建一个新网桥时,默认会创建一个与网桥同名的Internal Port。在OVS中,只有”internal”类型的设备才支持配置IP地址信息(并且在操作系统上可见),因此我们可以为br0接口配置一个IP地址,当然p0也可以配置IP地址
ip addr add 192.168.10.11/24 dev br0
ip link set br0 up
#添加默认路由
ip route add default via 192.168.10.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-ext中的Port phy-br-ext与br-int中的Port int-br-ext是一对Patch Port
可以使用ovs-vsctl创建patch设备,如下创建两个网桥br0,br1,然后使用一对Patch Port连接它们
ovs-vsctl add-br br0
ovs-vsctl add-br br1
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
结果如下
ovs-vsctl show
Bridge "br0"
Port "br0"
Interface "br0"
type:internal
Port "patch0"
Interface "patch0"
type:patch
options:{peer="patch1"}
Bridge "br1"
Port "br1"
Interface "br1"
type:internal
Port "patch1"
Interface "patch1"
type:patch
options:{peer="patch0"}
OVS中支持添加隧道(Tunnel)端口,常见隧道技术有两种gre或vxlan。隧道技术是在现有的物理网络之上构建一层虚拟网络,上层应用只与虚拟网络相关,以此实现的虚拟网络比物理网络配置更加灵活,并能够实现跨主机的L2通信以及必要的租户隔离。不同隧道技术其大体思路均是将以太网报文使用隧道协议封装,然后使用底层IP网络转发封装后的数据包,其差异性在于选择和构造隧道的协议不同。Tunnel在OpenStack中用作实现大二层网络以及租户隔离,以应对公有云大规模,多租户的复杂网络环境。
OpenStack是多节点结构,同一子网的虚拟机可能被调度到不同计算节点上,因此需要有隧道技术来保证这些同子网不同节点上的虚拟机能够二层互通,就像他们连接在同一个交换机上,同时也要保证能与其它子网隔离。
OVS在计算和网络节点上建立隧道Port来连接各节点上的网桥br-int,这样所有网络和计算节点上的br-int互联形成了一个大的虚拟的跨所有节点的逻辑网桥(内部靠tunnel id或VNI隔离不同子网),这个逻辑网桥对虚拟机和qrouter是透明的,它们觉得自己连接到了一个大的br-int上。从某个计算节点虚拟机发出的数据包会被封装进隧道通过底层网络传输到目的主机然后解封装。
上面网桥br-tun中Port “vxlan-080058ca"就是一个vxlan类型tunnel端口。下面使用两台主机测试创建vxlan隧道
#主机192.168.7.21上
ovs-vsctl add-br br-vxlan
#主机192.168.7.23上
ovs-vsctl add-br br-vxlan
#主机192.168.7.21上添加连接到7.23的Tunnel Port
ovs-vsctl add-port br-vxlan tun0 --set Interface tun0 type=vxlan options:remote_ip=192.168.7.23
#主机192.168.7.23上添加连接到7.21的Tunnel Port
ovs-vsctl add-port br-vxlan tun0 --set Interface tun0 type=vxlan options:remote_ip=192.168.7.21
然后,两个主机上桥接到br-vxlan的虚拟机就像连接到同一个交换机一样,可以实现跨主机的L2连接,同时又完全与物理网络隔离。
Interface是连接到Port的网络接口设备,是OVS与外部交换数据包的组件,在通常情况下,Port和Interface是一对一的关系,只有在配置Port为 bond模式后,Port和Interface是一对多的关系。这个网络接口设备可能是创建Internal类型Port时OVS自动生成的虚拟网卡,也可能是系统的物理网卡或虚拟网卡(TUN/TAP)挂载在ovs上。 OVS中只有”Internal”类型的网卡接口才支持配置IP地址
Interface是一块网络接口设备,负责接收或发送数据包,Port是OVS网桥上建立的一个虚拟端口,Interface挂载在Port上。一个接口就是操作系统的一块网卡
当Open vSwitch创建一个新网桥时,默认会创建一个与网桥同名的Internal Port,同时也创建一个与Port同名的Interface。三位一体,所以操作系统里就多了一块网卡,但是状态是down的。
OpenFlow控制器。OVS可以同时接受一个或者多个OpenFlow控制器的管理。主要作用是下发流表(Flow Tables)到OVS,控制OVS数据包转发规则。控制器与OVS通过网络连接,不一定要在同一主机上
可以看到上面实例中三个网桥br-int,br-ext,br-tun都连接到控制器Controller “tcp:127.0.0.1:6633上
OVS内核模块,负责执行数据交换。由于流可能非常复杂,对每个进来的数据包都去尝试匹配所有流,效率会非常低,所以有了datapath这个东西。Datapath是流的一个缓存,会把流的执行结果保存起来,当下次遇到匹配到同一条流的数据包,直接通过datapath处理。考虑到转发效率,datapath完全是在内核态实现的,并且默认的超时时间非常短,大概只有3秒左右。
ovs-vsctl是一个管理或配置ovs-vswitchd的高级命令行工具,高级是说其操作对用户友好,封装了对数据库的操作细节。它是管理OVS最常用的命令,除了配置flows之外,其它大部分操作比如Bridge/Port/Interface/Controller/Database/Vlan等都可以完成
#添加网桥br0
ovs-vsctl add-br br0
#列出所有网桥
ovs-vsctl list-br
#添加一个Port p1到网桥br0
ovs-vsctl add-port br0 p1
#查看网络br0上所有Port
ovs-vsctl list-ports br0
#获取br0网桥的Openflow控制器地址,没有控制器则返回空
ovs-vsctl get-controller br0
#设置OpenFlow控制器,控制器地址为192.168.1.10,端口为6633
ovs-vsctl set-controller br0 tcp:192.168.1.10:6633
#移除controller
ovs-vsctl del-controller br0
#删除网桥br0
ovs-vsctl del-br br0
#设置端口p1的vlan tag为100
ovs-vsctl set Port p1 tag=100
#设置端口p0类型为internal
ovs-vsctl set Interface p0 type=internal
#添加vlan10端口,并设置vlan tag为10,Port类型为Internal
ovs-vsctl add-port br0 vlan10 tag=10 -- set Interface vlan10 type=internal
#添加隧道端口gre0,类型为gre,远端IP为1.2.3.4
ovs-vsctl add-port br0 gre0 -- set Interface gre0 type=gre options:remote_ip=1.2.3.4
ovsdb-tool是一个专门管理OVS数据库文件的工具,不常用,它不直接与ovsdb-server进程通信
#可以使用此工具创建并初始化database文件
ovsdb-tool create [db][schema]
#可以使用ovsdb-client get-schema [database]获取某个数据库的schema(json格式)
#可以查看数据库更改记录,具体到操作命令,这个比较有用
ovsdb-tool show-log -m
record 48: 2017-01-07 03:34:15.147 "ovs-vsctl: ovs-vsctl --timeout=5 -- --if-exists del-port tapcea211ae-10"
table Interface row "tapcea211ae-10" (151f66b6):
delete row
table Port row "tapcea211ae-10" (cc9898cd):
delete row
table Bridge row "br-int" (fddd5e27):
table Open_vSwitch row a9fc1666 (a9fc1666):
record 49: 2017-01-07 04:18:23.671 "ovs-vsctl: ovs-vsctl --timeout=5 -- --if-exists del-port tap5b4345ea-d5 -- add-port br-int tap5b4345ea-d5 -- set Interface tap5b4345ea-d5 "external-ids:attached-mac=\"fa:16:3e:50:1b:5b\"" -- set Interface tap5b4345ea-d5 "external-ids:iface-id=\"5b4345ea-d5ea-4285-be99-0e4cadf1600a\"" -- set Interface tap5b4345ea-d5 "external-ids:vm-id=\"0aa2d71e-9b41-4c88-9038-e4d042b6502a\"" -- set Interface tap5b4345ea-d5 external-ids:iface-status=active"
table Port insert row "tap5b4345ea-d5" (4befd532):
table Interface insert row "tap5b4345ea-d5" (b8a5e830):
table Bridge row "br-int" (fddd5e27):
table Open_vSwitch row a9fc1666 (a9fc1666):
...
ovsdb-client是ovsdb-server进程的命令行工具,主要是从正在运行的ovsdb-server中查询信息,操作的是数据库相关
#列出主机上的所有databases,默认只有一个库Open_vSwitch
ovsdb-client list-dbs
#获取指定数据库的schema信息
ovsdb-client get-schema [DATABASE]
#列出指定数据库的所有表
ovsdb-client list-tables [DATABASE]
#dump指定数据库所有数据,默认dump所有table数据,如果指定table,只dump指定table数据
ovsdb-client dump [DATABASE] [TABLE]
#监控指定数据库中的指定表记录改变
ovsdb-client monitor DATABASE TABLE
ovs-ofctl是专门管理配置OpenFlow交换机的命令行工具,我们可以用它手动配置OVS中的OpenFlow flows,注意其不能操作datapath flows和”hidden” flows
#查看br-tun中OpenFlow flows
ovs-ofctl dump-flows br-tun
#查看br-tun端口信息
ovs-ofctl show br-tun
#添加新的flow:对于从端口p0进入交换机的数据包,如果它不包含任何VLAN tag,则自动为它添加VLAN tag 101
ovs-ofctl add-flow br0 "priority=3,in_port=100,dl_vlan=0xffff,actions=mod_vlan_vid:101,normal"
#对于从端口3进入的数据包,若其vlan tag为100,去掉其vlan tag,并从端口1发出
ovs-ofctl add-flow br0 in_port=3,dl_vlan=101,actions=strip_vlan,output:1
#添加新的flow: 修改从端口p1收到的数据包的源地址为9.181.137.1,show 查看p1端口ID为100
ovs-ofctl add-flow br0 "priority=1 idle_timeout=0,in_port=100,actions=mod_nw_src:9.181.137.1,normal"
#添加新的flow: 重定向所有的ICMP数据包到端口 p2
ovs-ofctl add-flow br0 idle_timeout=0,dl_type=0x0800,nw_proto=1,actions=output:102
#删除编号为 100 的端口上的所有流表项
ovs-ofctl del-flows br0 "in_port=100"
在安装open vswitch的主机上有两块网卡,分别为eth0、eth1,把这两块网卡挂接到open vswitch的网桥上,然后有两台物理机host1、host2分别连接到eth0和eth1上,实现这两台物理机的通信。构建结果图如下:
执行以下命令:
ovs-vsctl add-br br0 #建立一个名为br0的open vswitch网桥
ovs-vsctl add-port br0 eth0 #把eth0挂接到br0中
ovs-vsctl add-port br0 eth1 #把eth1挂接到br0中
在安装open vswitch的主机上安装两个虚拟机,把两个虚拟机的网卡都挂接在open vswitch的网桥上,实现两台虚拟机的通信,构建结果图如下:
执行以下命令:
ovs-vsctl add-br br0 #建立一个名为br0的open vswitch网桥
如果使用vbox或virt-manager把bridge设置为br0即可,如果使用cli kvm则先创建两个文件,用于虚拟网卡的添加与删除。假设这两个文件分别为/etc/ovs-ifup和/etc/ovs-ifdown,则向这两个文件中写入以下内容:
/etc/ovs-ifup
#!/bin/sh
switch='br0'
/sbin/ifconfig $1 0.0.0.0 up
ovs-vsctl add-port $(switch) $1
/etc/ovs-ifdown
#!/bin/sh
switch='br0'
/sbin/ifconfig $1 0.0.0.0 down
ovs-vsctl del-port $(switch) $1
使用以下命令建立虚拟机
kvm -m 512 -net nic,macaddr=00:11:22:33:44:55 \
-net tap,script=/etc/ovs-ifup,downscript=/etc/ovs-ifdown \
-drive file=/path/to/disk-image,boot=on
kvm -m 512 -net nic,macaddr=11:22:33:44:55:66 \
-net tap,script=/etc/ovs-ifup,downscript=/etc/ovs-ifdown-drive \
file=/path/to/disk-image,boot=on
在装有open vswitch的主机上有一个物理网卡eth0,一台主机通过网线和eth0相连,在open vswitch的主机上还装有一台虚拟机,把此虚拟机和连接到eth0的主机挂接到同一个网桥上,实现两者之间的通信,构建结果图如下:
执行命令:
ovs-vsctl add-br br0 #建立一个名为br0的open vswitch网桥
ovs-vsctl add-port br0 eth0 #把eth0挂接到br0中
kvm -m 512 -net nic,macaddr=00.11.22.33.44.55-net \
tap,script=/etc/ovs-ifup,downscript=/etc/ovs-ifdown-drive \
file=/path/to/disk-image,boot=on #ovs-ifup和ovs-ifdown和上一节相同
以上操作都是将多个主机(物理机或虚拟机)连接到同一个网桥上,实现它们之间的通信,但是要构建复杂的网络,就需要多个网桥,在装有open vswitch的主机上建立两个网桥,实现它们之间的连接,构建结果如下:
执行命令:
ovs-vsctl add-br br0 #添加一个名为br0的网桥
ovs-vsctl add-br br1 #添加一个名为br1的网桥
ovs-vsctl add-port br0 patch-to-br1 #为br0添加一个虚拟端口
ovs-vsctl set interface patch-to-br1 type=patch #把patch-to-br1的类型设置为patch
ovs-vsctl set interface patch-to-br1 options:peer=patch-to-br0 #把对端网桥和此网桥连接的端口名称设置为patch-to-br0
ovs-vsctl add-port br1 patch-to-br0 #为br0添加一个虚拟端口
ovs-vsctl set interface patch-to-br0 type=patch #把patch-to-br0的类型设置为patch
ovs-vsctl set interface patch-to-br0 options:peer=patch-to-br1 #把对端网桥和此网桥连接的端口名称设置为patch-to-br1
在两台机器上分别安装上open vswitch并创建网桥,分别为两个网桥添加物理网卡,然后通过网线连接两个网桥,实现两个网桥之间的互通。构建结果图如下:
执行命令:
host1
ovs-vsctl add-br br0 #添加名为br0的网桥
ovs-vsctl add-port br0 eth0 #把eth0挂接到br0上
host2
ovs-vsctl add-br br0 #添加名为br0的网桥
ovs-vsctl add-port br0 eth0 #把eth0挂接到br0上
然后使用网线把host1的eth0和host2的eth0相连即可。
使用上边五种方法的组合就可以构建出各种复杂的网络,为各种实验提供网络的支持。
flows是OVS进行数据转发策略控制的核心数据结构,区别于Linux Bridge是个单纯基于MAC地址学习的二层交换机,flows的存在使OVS作为一款SDN交换机成为云平台网络虚拟机化主要组件
OVS中有多种flows存在,用于不同目的,但最主要的还是OpenFlow flows这种,文中未明确说明的flows都是指OpenFlow flows
OVS中最重要的一种flows,Controller控制器下发的就是这种flows,OVS架构部分已经简单介绍过,关于OpenFlow 的具体使用,会在另一篇文章中说明
OVS在使用OpenFlow flows时,需要与OpenFlow控制器建立TCP连接,若此TCP连接不依赖OVS,即没有OVS依然可以建立连接,此时就是out-of-band control模式,这种模式下不需要"hidden” flows。
但是在in-band control模式下,TCP连接的建立依赖OVS控制的网络,但此时OVS依赖OpenFLow控制器下发的flows才能正常工作,没法建立TCP连接也就无法下发flows,这就产生矛盾了,因此需要存在一些"hidden” flows,这些"hidden" flows保证了TCP连接能够正常建立。关于in-band control详细介绍,参考OVS官方文档Design Decisions In Open vSwitch 中In-Band Control部分,“hidden” flows优先级高于OpenFlow flows,它们不需要手动设置。可以使用ovs-appctl查看这些flows,下面命令输出内容包括OpenFlow flows,"hidden" flows
ovs-appctl bridge/dump-flows
datapath flows是datapath内核模块维护的flows,由内核模块维护意味着我们并不需要去修改管理它。与OpenFlow flows不同的是,它不支持优先级,并且只有一个表,这些特点使它非常适合做缓存。与OpenFlow一样的是它支持通配符,也支持指令集(多个action)
datapath flows可以来自用户空间ovs-vswitchd缓存,也可以是datapath内核模块进行MAC地址学习到的flows,这取决与OVS是作为SDN交换机,还是像Linux Bridge那样只是一个简单基于MAC地址学习的二层交换机
我们可以修改和配置的是OpenFlow flows。datapath flow和"hidden" flows由OVS自身管理,我们不必去修改它。当然,调试场景下还是可以使用工具修改的
介绍下上面三种flows管理工具,不具体说明,具体使用可以查看相关man手册
ovs-ofctl dump-flows <br>打印指定网桥内的所有OpenFlow flows,可以存在多个流表(flow tables),按表顺序显示。不包括"hidden" flows。这是最常用的查看flows命令,当然这条命令对所有OpenFlow交换机都有效,不单单是OVSovs-appctl bridge/dump-flows <br>打印指定网桥内所有OpenFlow flows,包括"hidden" flows,in-band control模式下排错可以用到ovs-dpctl dump-flows [dp]打印内核模块中datapath flows,[dp]可以省略,默认主机中只有一个datapathsystem@ovs-systemman手册可以找到非常详细的用法说明,注意ovs-ofctl管理的是OpenFlow flows
每条流表项Flow(流表规则)由一系列字段组成,分为基本字段、条件字段和动作字段三部分:
基本字段包括生效时间duration_sec、所属表项table_id、优先级priority、处理的数据包数n_packets,空闲超时时间idle_timeout等。空闲超时时间idle_timeout以秒为单位,超过设置的空闲超时时间后该流规则将被自动删除,空闲超时时间设置为0表示该流规则永不过期,idle_timeout将不包含于ovs-ofctl dump-flows brname的输出中。
- cookie=value 流表标识字段,cookie字段有两种书写方式:cookie=value和cookie=value/mask。mask中对应位为1时cookie中值相应的位须严格匹配,为0时cookie中值对应的位通配,当mask为-1时,必须严格匹配cookie值。
- duration=value 流表生效时间,标识流表从下发到现在所持续的时间
- priority=priority 标识流表的优先级,范围为0-65535,值越大,优先级越高
- n_packets 标识流表匹配包数
- n_bytes 标识流表匹配字节数
- idle_timeout=sec 流表空闲超时时间,流表会在空闲时间达到给定的时间时被删除。设置为0(默认值)时,流表不会因空闲时间被删除。
- hard_timeout=sec 流表可存在的时间。设置此值后,流表会在到达给定时间后被删除。
- idle_age=sec 流表空闲时间
- hard_age=sec 流表存在时间。此字段与duration字段的区别在当流表被修改后,会重新设置hard_timer但是不会重置duration
- ip_frag=frag_type 当dl_type指定为IP或者IPv6,frag_type指定匹配的IP分片包或者非分片包的匹配
- frag_type支持的值为: no: 仅匹配非分片报文 yes:匹配所有分片报文 first:仅匹配offset为0的分片报文
- later: 仅匹配offset非0的分片报文 not_later:匹配非分片报文和offset为0的分片报文
条件字段包括输入端口号in_port、源目的mac地址dl_src/dl_dst、源目的ip地址nw_src/nw_dst、数据链路层包类型dl_type、网络层协议类型nw_proto等。可以为这些字段的任意组合,但在网络分层结构中底层的字段未给出确定值时上层的字段不允许给确定值,即一条流规则中允许底层协议字段指定为确定值,高层协议字段指定为通配符(不指定即为匹配任何值),而不允许高层协议字段指定为确定值,而底层协议字段却为通配符(不指定即为匹配任何值),否则,ovs-vswitchd 中的流规则将全部丢失,网络无法连接。
动作字段包括正常转发normal(正常的二层转发设备,即根据目标MAC进行转发)、定向到某交换机端口output:port、丢弃drop、更改源目的mac地址mod_dl_src/mod_dl_dst等,一条流规则可有多个动作,动作执行按指定的先后顺序依次完成,例如actions=mod_vlan_vid:1,resubmit(,10)。
- in_port=port 传递数据包的端口的 OpenFlow 端口编号。每个port在 Open vSwitch中会有一个内部的编号。可以通过命令
ovs-ofctl show <BRIDGE>查看 port编号。 - dl_vlan=vlan 数据包的 VLAN Tag 值,范围是 0-4095,0xffff 代表不包含 VLAN Tag 的数据包
- dl_src=和dl_dst= 匹配源或者目标的 MAC 地址 01:00:00:00:00:00/01:00:00:00:00:00 代表广播地址 00:00:00:00:00:00/01:00:00:00:00:00 代表单播地址。匹配指定的链路层MAC地址,MAC地址格式为ADDR/MASK,当MASK值为01:00:00:00:00:00时,仅匹配多播位。当dl_dst=01:00:00:00:00:00/01:00:00:00:00:00时,匹配所有的组播报文和广播报文。dl_dst=00:00:00:00:00:00/01:00:00:00:00:00匹配所有的单播报文。
- dl_type=ethertype 匹配以太网协议类型,其中: dl_type=0x0800 代表 IPv4 协议 ;dl_type=0x086dd 代表 IPv6 协议; dl_type=0x0806 代表 ARP 协议;
- dl_vlan=vlan 匹配802.1Q类型(即vlan)数据包
- nw_src=ip[/netmask]和nw_dst=ip[/netmask] 当 dl_typ=0x0800 时,匹配源或者目标的 IPv4 地址,可以使 IP 地址或者域名。当dl_type=0x0800或指定ip时,匹配数据包的源、目的IP地址 当dl_type=0x0806或指定arp时,匹配ARP数据包的ar_spa或者ar_tpa字段
- nw_proto=proto 和 dl_type 字段协同使用。当 dl_type=0x0800 时,匹配IPv4协议族的协议,例如tcp,udp,icmp等;当 dl_type=0x086dd 代表 IPv6 协议编号
- nw_tos=tos 匹配IP Tos/DSCP或者IPv6的tos字段,值为0-255
- nw_ecn=ecn 匹配IP或者IPv6的ecn字段,值为0~3
- nw_ttl=ttl 匹配TTL值
- table=number 指定要使用的流表的编号,范围是 0-254。在不指定的情况下,默认值为 0。通过使用流表编号,可以创建或者修改多个 Table 中的 Flow
- reg=value[/mask] 交换机中的寄存器的值。当一个数据包进入交换机时,所有的寄存器都被清零,用户可以通过 Action 的指令修改寄存器中的值
- in_port=port 标识匹配接收数据包的端口号
- dl_type=ethertype 匹配数据包的二层协议类型,IP数据包为0x0800,IPv6数据包为0x86dd,ARP数据包为0x0806
- tp_src=port
- tp_dst=port 若指定了udp或者tcp协议,则匹配udp/tcp的端口号
- icmp_type=type
- icmp_code=code 若指定了icmp或者icmpv6协议,则匹配对应的icmp 类型或者code字段
- arp_sha=xx:xx:xx:xx:xx:xx
- arp_tha=xx:xx:xx:xx:xx:xx 当设置dl_type为ARP或者RARP,则arp_sha和arp_tha匹配数据包的源、目的MAC地址
| 缩写 | 等价写法 |
|---|---|
| ip | Same as dl_type=0x0800. |
| icmp | Same as dl_type=0x0800,nw_proto=1. |
| tcp | Same as dl_type=0x0800,nw_proto=6. |
| udp | Same as dl_type=0x0800,nw_proto=17. |
| arp | Same as dl_type=0x0806. |
| rarp | Same as dl_type=0x8035. |
例如:
ovs-appctl ofproto/trace br-int in_port=tapc6639265-88,dl_src=fa:16:3e:4e:7d:77,dl_dst=fa:16:3e:9a:a5:50,ip,nw_src=192.168.2.86,nw_dst=192.168.2.35,nw_proto=1 -generate
- output:port: 输出数据包到指定的端口。port 是指端口的 OpenFlow 端口编号。例如
actions=output:6003 - mod_vlan_vid:vlan_vid 修改数据包的vlan tag
- mod_vlan_pcp:vlan_pcp 修改数据包的vlan priority
- strip_vlan: 移除数据包中的 VLAN tag(如果数据包中存在vlan tag,则剥离vlan tag)
- mod_dl_src/ mod_dl_dest: 修改源或者目标的 MAC 地址信息
- mod_nw_src/mod_nw_dst: 修改源或者目标的 IPv4 地址信息
- resubmit([port],[table]): 替换流表的 in_port 字段,并在新的表table中重新进行匹配
- load:value−>dst[start…end]: 写数据到指定的字段,例如:
load:0->NXM_OF_VLAN_TCI[]表示将vlan号改为0(vlan=0表示去掉vlan号);例如load:0x1f7->NXM_NX_REG5[],这个NXM_NX_REG5是指openflow协议定义的一些变量,叫寄存器,用在流表匹配过程中临时存储一些中间数据,供后续使用。 - set_field:value−>dst[start…end]:load和set_field的作用基本上是等同的,都是将任意值赋值给field,或者赋值给field的某些位。例如
set_field:100.114.6.63->ip_dst - move相比上面两个action,它只能将field的值赋值给另一个field,src和dst都必须是field。
- enqueue:port:queue 将数据包入队到指定端口的指定队列里
- normal 将数据包按照设备上的正常L2/L3层处理方式进行处理
- flood 将数据包发送到交换机上除接收接口和禁止flood的接口外的所有接口
- all 将数据包发送到除接收接口外的所有接口
- controller(key=value…) 将数据包作为PACKET IN消息发送到OpenFlow控制器。 支持的键值对: max_len=nbytes:限制发送到控制器的数据包长度字节数,默认情况是发送整个数据包;reason=reason:在PACKET IN消息中指明发送消息的原因,支持的reason为action(default),no_match和invalid_ttl; id=controller-id:指明控制器ID
- in_port 将数据包从接收的接口发送出去
- drop 丢弃数据包
- push_vlan:ethertype 为数据包添加新的vlan tag
- mod_tp_src:port 设置TCP或者UDP的源端口
- mod_tp_dst:port 设置TCP或UDP的目的端口
root@compute01:~# ovs-vsctl get interface tapf151b58d-70 ofport
6003
root@compute01:~# ovs-ofctl show br-int |grep tapf151b58d-70
6003(tapf151b58d-70): addr:fe:16:3e:d9:a1:4f
简单地说,流表的匹配遵循两条原则:
(1)优先级不同情况下,优先级高的先匹配,优先级低的后匹配,优先级的范围0~66535,数字越大则优先级越高;
(2)优先级相同情况下,当流表项具有相同的优先级,相同的actions,不同的匹配域粒度的情况下,按照流表项添加的先后顺序匹配,最先添加的流表项,数据流优先匹配,即按照添加的先后顺序进行匹配。
https://www.sdnlab.com/sdn-guide/14747.html
https://opengers.github.io/openstack/openstack-base-use-openvswitch/
https://blog.csdn.net/qq_29229567/article/details/102391283
https://www.cnblogs.com/wangjq19920210/p/11776824.html (推荐)
参考:
patch port:https://www.cnblogs.com/lausaa/p/6647261.html OpenFlow基础入门知识:https://blog.csdn.net/dwj_daiwenjie/article/details/87516136
http://t.zoukankan.com/dream397-p-12653074.html
https://blog.csdn.net/qq_20817327/article/details/116742937
https://blog.csdn.net/qq_34039018/article/details/88562102