1, 部署ovs
本节介绍如何设置Open vSwitch,方便后面与faucet联合起来使用,搭建整套流控制器和虚拟交换网络
1. 使用Git从open vswitch官网获取源码
2. 构建ovs
$./boot.sh
$./configure
$make-j4
3. 创建ovs 沙箱。使用沙箱的好处是可以避免跟本机在run的ovs冲突
$make sandbox
2. 部署faucet
通过docker 的方式部署faucet是最方便的手段
$mkdir -p /var/log/faucet/
$docker pull faucet/faucet:latest
$docker run -d \
--name faucet \
--restart=always \
-v /etc/faucet/:/etc/faucet/ \
-v /var/log/faucet/:/var/log/faucet/ \
-p 6653:6653 \
-p 9302:9302 \
faucet/faucet
Port 6653 用于OpenFlow下发流表, port 9302 用于Prometheus
3. 使用faucet和ovs建立虚拟网络
现在Open vSwitch和Faucet已经准备好了,我们将通过本教程受用faucet和ovs建立起一个L2的交换网络
我们将通过每一步详细介绍了解从顶部的Faucet到底部的数据平面层,所讨论的功能是如何工作的。从最高到最低级别,这些层和连接它们的软件组件是:
Faucet
作为系统中的最高级别,这是网络配置的来源。
Faucet可以连接到各种监视和性能工具,本教程我们将通过用于配置的Faucet.yaml和用于观察状态(如MAC学习和ARP解析)的Faucet.log来深入了解系统。
The OpenFlow subsystem in Open vSwitch
OpenFlow是由开放网络基金会(Open Networking Foundation)标准化的协议,像Faucet这样的控制器用它来控制Open vSwitch和其他交换机如何处理网络中的数据包。
我们将使用ovs-ofctl来观察或者修改Open vSwitch的OpenFlow行为。我们还将使用ovs-appctl(一个用于与ovs-vswitchd和其他开放的vSwitch守护进程进行通信的实用程序)来查询和控制运行中的ovs守护进程。
此外,默认情况下,OVS沙箱将OpenFlow的Open vSwitch日志记录级别提高到debug的水平,我们只需通过读取其日志文件就可以了解大量有关OpenFlow行为的信息。
Open vSwitch datapath
这实质上是为加速数据包处理而设计的高速缓存。Open vSwitch包括几个不同的数据路径,例如基于Linux内核的数据路径和仅限用户空间的数据路径(有时称为“ DPDK ”数据路径)。
我们将演示如何使用Open vSwitch功能来调试、排除故障和了解整个系统。
Switching
第2层(L2)交换是现代网络的基础。它也非常简单,是一个很好的起点,所以让我们在Faucet中设置一个带有一些VLAN的交换机,看看它在每一层是如何工作的。首先将以下内容输入inst/faucet.yaml:
dps:
switch-1:
dp_id: 0x1
timeout: 3600
arp_neighbor_timeout: 3600
interfaces:
1:
native_vlan: 100
2:
native_vlan: 100
3:
native_vlan: 100
4:
native_vlan: 200
5:
native_vlan: 200
vlans:
100:
200:
此配置文件定义了名为Switch-1的单个交换机(“数据路径”或“ DP ”)。交换机有五个端口,编号为1到5。端口1、2和3位于VLAN 100中,端口4和5位于VLAN 2中。Faucet可以通过其数据路径ID(dp_id: 0x1)来识别交换机。
现在重新启动Faucet,以使配置生效,例如:
$sudo docker restart faucet
假设配置更新成功,您现在应该在inst/faucet.log的末尾看到一个新行:
Sep 10 06:44:10 faucet INFO Add new datapath DPID 1 (0x1)
Faucet现在正在等待一个dp_id为0x1的交换机通过OpenFlow连接到它,因此我们的下一步是创建通过ovs创建一个虚拟交换机,并使其连接到Faucet。切换到签出ovs的终端,并使用make sandbox启动一个沙箱:
----------------------------------------------------------------------
You are running in a dummy Open vSwitch environment. You can use
ovs-vsctl, ovs-ofctl, ovs-appctl, and other tools to work with the
dummy switch.
Log files, pidfiles, and the configuration database are in the
"sandbox" subdirectory.
Exit the shell to kill the running daemons.
blp@sigabrt:~/nicira/ovs/tutorial(0)$
在sandbox中,创建一个交换机命名为br0,将其datapath-id设置为0x1,向其添加名为P1到P5的模拟端口,并告诉它连接到Faucet控制器:
$ ovs-vsctl add-br br0 \
-- set bridge br0 other-config:datapath-id=0000000000000001 \
-- add-port br0 p1 -- set interface p1 ofport_request=1 \
-- add-port br0 p2 -- set interface p2 ofport_request=2 \
-- add-port br0 p3 -- set interface p3 ofport_request=3 \
-- add-port br0 p4 -- set interface p4 ofport_request=4 \
-- add-port br0 p5 -- set interface p5 ofport_request=5 \
-- set-controller br0 tcp:127.0.0.1:6653 \
-- set controller br0 connection-mode=out-of-band
注意:Faucet需要端口处于“打开”状态才能对其进行配置。在低于2.11.0的Open vSwitch版本中,虚拟端口以关闭状态启动。需要强制他们使用以下ovs-appctl命令:
$ ovs-appctl netdev-dummy/set-admin-state up
现在,如果再次查看inst/faucet.log,应该会看到已经识别并配置了新交换机及其端口的Faucet:
Sep 10 06:45:03 faucet.valve INFO DPID 1 (0x1) switch-1 Cold start configuring DP
Sep 10 06:45:03 faucet.valve INFO DPID 1 (0x1) switch-1 Configuring VLAN 100 vid:100 ports:Port 1,Port 2,Port 3
Sep 10 06:45:03 faucet.valve INFO DPID 1 (0x1) switch-1 Configuring VLAN 200 vid:200 ports:Port 4,Port 5
Sep 10 06:45:24 faucet.valve INFO DPID 1 (0x1) switch-1 Port 1 (1) up
Sep 10 06:45:24 faucet.valve INFO DPID 1 (0x1) switch-1 Port 2 (2) up
Sep 10 06:45:24 faucet.valve INFO DPID 1 (0x1) switch-1 Port 3 (3) up
Sep 10 06:45:24 faucet.valve INFO DPID 1 (0x1) switch-1 Port 4 (4) up
Sep 10 06:45:24 faucet.valve INFO DPID 1 (0x1) switch-1 Port 5 (5) up
在Open vSwitch端,查看sandbox/ovs-vswitchd.log,可以看到许多相关活动。例如,下面是基本的OpenFlow会话设置和交换机端口和功能的Faucet探针:
rconn|INFO|br0<->tcp:127.0.0.1:6653: connecting...
vconn|DBG|tcp:127.0.0.1:6653: sent (Success): OFPT_HELLO (OF1.4) (xid=0x1):
version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05
vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_HELLO (OF1.3) (xid=0xdb9dab08):
version bitmap: 0x01, 0x02, 0x03, 0x04
vconn|DBG|tcp:127.0.0.1:6653: negotiated OpenFlow version 0x04 (we support version 0x05 and earlier, peer supports version 0x04 and earlier)
rconn|INFO|br0<->tcp:127.0.0.1:6653: connected
vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FEATURES_REQUEST (OF1.3) (xid=0xdb9dab09):
00040|vconn|DBG|tcp:127.0.0.1:6653: sent (Success): OFPT_FEATURES_REPLY (OF1.3) (xid=0xdb9dab09): dpid:0000000000000001
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS
vconn|DBG|tcp:127.0.0.1:6653: received: OFPST_PORT_DESC request (OF1.3) (xid=0xdb9dab0a): port=ANY
vconn|DBG|tcp:127.0.0.1:6653: sent (Success): OFPST_PORT_DESC reply (OF1.3) (xid=0xdb9dab0a):
1(p1): addr:aa:55:aa:55:00:14
config: 0
state: LIVE
speed: 0 Mbps now, 0 Mbps max
2(p2): addr:aa:55:aa:55:00:15
config: 0
state: LIVE
speed: 0 Mbps now, 0 Mbps max
3(p3): addr:aa:55:aa:55:00:16
config: 0
state: LIVE
speed: 0 Mbps now, 0 Mbps max
4(p4): addr:aa:55:aa:55:00:17
config: 0
state: LIVE
speed: 0 Mbps now, 0 Mbps max
5(p5): addr:aa:55:aa:55:00:18
config: 0
state: LIVE
speed: 0 Mbps now, 0 Mbps max
LOCAL(br0): addr:42:51:a1:c4:97:45
config: 0
state: LIVE
speed: 0 Mbps now, 0 Mbps max
之后,可以看到Faucet删除所有现有流程,然后开始添加新流程:
vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FLOW_MOD (OF1.3) (xid=0xdb9dab0f): DEL table:255 priority=0 actions=drop
vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FLOW_MOD (OF1.3) (xid=0xdb9dab10): ADD priority=0 cookie:0x5adc15c0 out_port:0 actions=drop
vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FLOW_MOD (OF1.3) (xid=0xdb9dab11): ADD table:1 priority=0 cookie:0x5adc15c0 out_port:0 actions=goto_table:2
vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FLOW_MOD (OF1.3) (xid=0xdb9dab12): ADD table:2 priority=0 cookie:0x5adc15c0 out_port:0 actions=goto_table:
...
OpenFlow层
让我们来看看Faucet设置的OpenFlow表。faucet表格布局为:
Table 0
Port-based ACLs
Table 1
Ingress VLAN processing
Table 2
VLAN-based ACLs
Table 3
Ingress L2 processing, MAC learning
Table 4
L3 forwarding for IPv4
Table 5
L3 forwarding for IPv6
Table 6
Virtual IP processing, e.g. for router IP addresses implemented by Faucet
Table 7
Egress L2 processing
Table 8
Flooding
我们dump流表,检查流表情况:
$ ovs-ofctl dump-flows br0
运行这个命令,它会产生许多额外的垃圾,使输出更难阅读。比如统计数据和“ cookie ”值都是相同的。此外,由于历史原因,ovs-ofctl默认使用OpenFlow 1.0. Faucet和大多数现代控制器使用OpenFlow 1.3,所以最好强制使用OpenFlow 1.3。方便起见,我们自己定义一个shell函数:
$dump-flows(){
ovs-ofctl-o openflow13--names--no-stat dump-flows “$@”\
|sed ' S/cookie=0x5ADC15C0,//'
}
我们还可以定义save-flows和diff-flows函数以供以后使用:
$save-flows(){
ovs-ofctl-oopenflow13--no-names--sort dump-flows “$@”
}
$diff-flows(){
ovs-ofctl-oopenflow13 diff-flows “$@”|sed ' s/cookie=0x5adc15c0//'
}
现在,让我们来看看我们得到的流以及它们的含义,如下所示:
$dump-flows br0
为了减少硬件交换机上的资源利用率,Faucet将尝试安装最小的OpenFlow表集,以匹配在Faucet.yaml中启用的功能。由于我们只启用了switching,因此最终将只有4个表。如果我们检查inst/faucet.log的内容,Faucet会告诉我们每个表的功能:
Sep 10 06:44:10 faucet.valve INFO DPID 1 (0x1) switch-1 table ID 0 table config dec_ttl: None exact_match: None match_types: (('eth_dst', True), ('eth_type', False), ('in_port', False), ('vlan_vid', False)) meter: None miss_goto: None name: vlan next_tables: ['eth_src'] output: True set_fields: ('vlan_vid',) size: 32 table_id: 0 vlan_port_scale: 1.5
Sep 10 06:44:10 faucet.valve INFO DPID 1 (0x1) switch-1 table ID 1 table config dec_ttl: None exact_match: None match_types: (('eth_dst', True), ('eth_src', False), ('eth_type', False), ('in_port', False), ('vlan_vid', False)) meter: None miss_goto: eth_dst name: eth_src next_tables: ['eth_dst', 'flood'] output: True set_fields: ('vlan_vid', 'eth_dst') size: 32 table_id: 1 vlan_port_scale: 4.1
Sep 10 06:44:10 faucet.valve INFO DPID 1 (0x1) switch-1 table ID 2 table config dec_ttl: None exact_match: True match_types: (('eth_dst', False), ('vlan_vid', False)) meter: None miss_goto: flood name: eth_dst next_tables: [] output: True set_fields: None size: 41 table_id: 2 vlan_port_scale: 4.1
Sep 10 06:44:10 faucet.valve INFO DPID 1 (0x1) switch-1 table ID 3 table config dec_ttl: None exact_match: None match_types: (('eth_dst', True), ('in_port', False), ('vlan_vid', False)) meter: None miss_goto: None name: flood next_tables: [] output: True set_fields: None size: 32 table_id: 3 vlan_port_scale: 2.1
目前,我们有:
Table 0 (vlan)
Ingress VLAN processing
Table 1 (eth_src)
Ingress L2 processing, MAC learning
Table 2 (eth_dst)
Egress L2 processing
Table 3 (flood)
Flooding
在表0中,我们看到流在每个端口(VLAN_TCI=0x0000/0x1FFF)上识别没有VLAN报头的数据包,push为端口配置的VLAN,并继续流向表3。还有一个回程流以丢弃其他数据包,这实际上意味着如果任何接收的数据包已经具有VLAN报头,则它将被丢弃:
priority=9000,in_port=p1,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4196->vlan_vid,goto_table:1
priority=9000,in_port=p2,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4196->vlan_vid,goto_table:1
priority=9000,in_port=p3,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4196->vlan_vid,goto_table:1
priority=9000,in_port=p4,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4296->vlan_vid,goto_table:1
priority=9000,in_port=p5,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4296->vlan_vid,goto_table:1
priority=0 actions=drop
注意
语法设置_字段:4196->VLAN_VID很奇怪,而且有些误导。OpenFlow 1.3将VLAN_VID字段定义为13位字段,其中,如果存在VLAN报头,则将第12位设置为1。因此,由于4196是0x1064,该动作设置VLAN值0x64,其十进制是100。
表1从丢弃一些不适当的信息包的流开始,在这种情况下,EtherType 0x9000(Ethernet Configuration Testing Protocol)不应由交换机转发:
table=1, priority=9099,dl_type=0x9000 actions=drop
表1主要用于MAC学习,但控制器尚未学习任何MAC地址。表1也会丢弃一些更不合适的数据包,例如那些来自广播源地址的数据包:
table=1, priority=9099,dl_src=ff:ff:ff:ff:ff:ff actions=drop
table=1, priority=9001,dl_src=0e:00:00:00:00:01 actions=drop
table=1, priority=9000,dl_vlan=100 actions=CONTROLLER:96,goto_table:2
table=1, priority=9000,dl_vlan=200 actions=CONTROLLER:96,goto_table:2
table=1, priority=0 actions=goto_table:2
表2用于将数据包定向到已学习的MAC,但Faucet尚未学习任何MAC,因此它只是将所有数据包发送到表3:
table=2, priority=0 actions=goto_table:3
表3丢弃了更多我们不想转发的数据包,在本例中为STP报文:
table=3, priority=9099,dl_dst=01:00:0c:cc:cc:cd actions=drop
table=3, priority=9099,dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0 actions=drop
表3实现了泛洪、广播和多播。广播和泛洪的流程很容易理解:如果数据包来自给定端口,并且需要泛洪或广播,则将其输出到同一VLAN中的所有其他端口:
table=3, priority=9004,dl_vlan=100,dl_dst=ff:ff:ff:ff:ff:ff actions=pop_vlan,output:p1,output:p2,output:p3
table=3, priority=9004,dl_vlan=200,dl_dst=ff:ff:ff:ff:ff:ff actions=pop_vlan,output:p4,output:p5
table=3, priority=9000,dl_vlan=100 actions=pop_vlan,output:p1,output:p2,output:p3
table=3, priority=9000,dl_vlan=200 actions=pop_vlan,output:p4,output:p5
还有一些用于处理一些标准形式的多播的流,以及回退丢弃流:
table=3, priority=9003,dl_vlan=100,dl_dst=33:33:00:00:00:00/ff:ff:00:00:00:00 actions=pop_vlan,output:p1,output:p2,output:p3
table=3, priority=9003,dl_vlan=200,dl_dst=33:33:00:00:00:00/ff:ff:00:00:00:00 actions=pop_vlan,output:p4,output:p5
table=3, priority=9001,dl_vlan=100,dl_dst=01:80:c2:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p1,output:p2,output:p3
table=3, priority=9002,dl_vlan=100,dl_dst=01:00:5e:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p1,output:p2,output:p3
table=3, priority=9001,dl_vlan=200,dl_dst=01:80:c2:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p4,output:p5
table=3, priority=9002,dl_vlan=200,dl_dst=01:00:5e:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p4,output:p5
table=3, priority=0 actions=drop
Tracing
OVS允许我们可以查看更具体的内容:跟踪特定数据包通过Open vSwitch所采用的路径。我们可以使用ofproto/trace命令来跟踪数据流。此命令是我们使用ovs-appctl直接发送到ovs-vswitchd demon程序的命令。
注意
ovs-appctl实际上是一个非常简单的JSON-RPC客户端,还可以使用其他一些调用JSON-RPC的实用程序,或者从程序中将其作为API访问。
ovs-vswitchd(8)手册页有很多关于如何使用ofproto/trace的详细信息,但让我们从一个简单的示例开始。
让我们来看看这个小例子的完整输出:
$ovs-appctl ofproto/trace br0 in_port=p1
Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
bridge("br0")
-------------
0. in_port=1,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
push_vlan:0x8100
set_field:4196->vlan_vid
goto_table:1
1. dl_vlan=100, priority 9000, cookie 0x5adc15c0
CONTROLLER:96
goto_table:2
2. priority 0, cookie 0x5adc15c0
goto_table:3
3. dl_vlan=100, priority 9000, cookie 0x5adc15c0
pop_vlan
output:1
>> skipping output to input port
output:2
output:3
Final flow: unchanged
Megaflow: recirc_id=0,eth,in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Datapath actions: push_vlan(vid=100,pcp=0),userspace(pid=0,controller(reason=1,dont_send=1,continuation=0,recirc_id=1,rule_cookie=0x5adc15c0,controller_id=0,max_len=96)),pop_vlan,2,3
输出的第一行,以flow:开头,只是以更详细的形式重复我们的请求,包括被置零的L2字段。
Bridge(“br0”)下的每个编号项目都显示了数据流在表中的流向和操作。例如,我们在表0中看到,数据包与push_vlan报头的流相匹配,将VLAN ID设置为100,并在表1中继续进行进一步处理。在表1中,数据包被发送到控制器以允许进行MAC学习,然后表3将数据包泛洪到同一VLAN中的其他端口。
接下来是摘要信息。显示报文从进入br0以后到出br0整个过程,数据包没有发生变化(总体而言,开始报文打上VLAN tag,然后出去时有去掉了VLAN tag),因此最终报文未发生变化。