OpenvSwitch flow
OpenFlow 是用于管理交换机流表的协议,ovs-ofctl 则是 OVS 提供的命令行工具。在没有配置 OpenFlow 控制器的模式下,可以使用 ovs-ofctl 命令通过 OpenFlow 协议去连接 OVS,创建、修改或删除 OVS 中的流表项,并对 OVS 的运行状况进行动态监控。
ovs-ofctl流表操作命令
ovs-ofctl add−flow/add−flows/mod−flows “流表匹配条件,actions=[target][,target…]”
流表匹配条件
在 OVS 中,流表项作为 ovs-ofctl 的参数,采用如下的格式:字段=值。如果有多个字段,可以用逗号或者空格分开
流表执行的动作
流表可以有多个执行动作,是从左向右以此执行,常用动作如下:
- output:port: 输出数据包到指定的端口。port 是指端口的 OpenFlow 端口编号
- group:group_id 输出数据包到openflow group。group_id是指openflow group的id
enqueue:port:queue 将数据包放到openflow port端口的queue号队列中
mod_vlan_vid: vlan_id 修改数据包中的 VLAN tag为vlan_id,如果数据包中无tag,则添加。如果数据包中已经是vlan_id,同时调整期vlan优先级为0
- strip_vlan: 移除数据包中的 VLAN tag
- mod_dl_src/ mod_dl_dest: 修改源或者目标的 MAC 地址信息
- mod_nw_src/mod_nw_dst: 修改源或者目标的 IPv4 地址信息
- mod_tp_src/mod_tp_dst: 将数据包的TCP/UDP/SCTP源或则目的端口
drop 将数据包丢弃
resubmit:port: 替换流表的 in_port 字段,并重新进行匹配
- load:value−>dst[start..end]: 写数据到指定的字段
- move:src[start..end]−>dst[start..end] 含义未探究清楚、待定
learn(argument[,argument]…) 含义未探究清楚、待定
normal 按照常规L2/L3处理流程处理数据包
- flood 将数据包输出到除该数据包输入口外和不可被flooding端口外的所有物理端口
- all 将数据包输出到除了该数据包的输入口外的所有物理口
- local 将数据包输出到与bridge同名的端口
- in_port 将数据包输出到其输入口
controller(key=value) 将数据包以“packet in”消息形式发给openflow控制器
max_len=nbytes 将数据包的nbytes字节数据发给控制器
reason=reason 指明“packet in” reason; action(默认reason)、no_match、invalid_ttl
id=controller-id 指明要发送给的控制器idmod_nw_tos:tos 修改ip头的服务类型tos中的高六位(修改数值4的倍数[0,255]之间)
- mod_nw_ecn:ecn 修改ip头的服务类型tos中底2位
- mod_nw_ttl:ttl 修改TTL[0,255]
- set_tunnel:id
flow table使用实例
实验要求
创建一个Virtual Switch br0
包含下面四个Port:
first_br, truck port
second_br, VLAN 20
third_br, forth_br VLAN 30包含五个flow table:
Table 0: Admission control.
Table 1: VLAN input processing.
Table 2: Learn source MAC and VLAN for ingress port.
Table 3: Look up learned port for destination MAC and VLAN.
Table 4: Output processing
实验拓扑
1 | +----+ +----+ |
实验拓扑基础环境实现脚本
1 | ovs-vsctl add-br br0 |
脚本执行完成后,查看flow策略1
2
3root@controller-VirtualBox:~# ovs-ofctl dump-flows br0
NXST_FLOW reply (xid=0x4):
cookie=0x0, duration=52.681s, table=0, n_packets=0, n_bytes=0, idle_age=52, priority=0 actions=NORMA
flow table 0 策略(基础策略,所有数据包都先经过我)
数据包会首先进入flow table0,因此这里的flow table策略相当于总开关
多播不允许进入ovs br0
1 | ovs-ofctl add-flow br0 "table=0, dl_src=01:00:00:00:00:00/01:00:00:00:00:00, actions=drop" |
STP报文丢弃
1 | ovs-ofctl add-flow br0 "table=0, dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0, actions=drop" |
如果非上述两种类数据包交给table 1策略处理
1 | ovs-ofctl add-flow br0 "table=0, priority=0, actions=resubmit(,1)" |
测试
- 命中 table=0 cookie=0 dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0
OpenFlow actions=drop
1 | root@controller-VirtualBox:~# ovs-appctl ofproto/trace br0 in_port=1,dl_dst=01:80:c2:00:00:05 |
- 命中table=0 cookie=0 priority=0 OpenFlow actions=resubmit(,1)
1 | root@controller-VirtualBox:~# ovs-appctl ofproto/trace br0 in_port=1,dl_dst=01:80:c2:00:00:10 |
flow table 1 策略(搭建含有trunk、vlan概念的基本组网信息)
table 1 默认策略为数据包丢弃
1 | ovs-ofctl add-flow br0 "table=1, priority=0, actions=drop" |
table 1 从first_br(in_port=1)进入的数据包继续交给table 2处理
1 | ovs-ofctl add-flow br0 "table=1, priority=99, in_port=1, actions=resubmit(,2)" |
测试:从first_br进入br0 tag为5的数据包直接交给table2处理 1
2
3
4
5
6
7
8
9
10
11
12root@controller-VirtualBox:~# ovs-appctl ofproto/trace br0 in_port=1,vlan_tci=5
Bridge: br0
Flow: in_port=1,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Rule: table=0 cookie=0 priority=0
OpenFlow actions=resubmit(,1)
Resubmitted flow: in_port=1,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
Resubmitted odp: drop
Resubmitted megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Rule: table=1 cookie=0 priority=99,in_port=1
OpenFlow actions=resubmit(,2)
从其它口进入数据包,没有tag加上对应tag,有tag则不动
1 | ovs-ofctl add-flows br0 - <<'EOF' |
执行完上述标签操作后,其拓扑图更改如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 +----+ +----+
| | first_if | | second_if
+----+ +----+
| |
| |
| |
| | vlan 20
trunk口 | |
| first_br | second_br
+---+ +---+
+-------------------------------------------------------+
| +---+ +---+ |
| |
| |
| br0 |
| |
| |
| +---+ +---+ |
+-------------------------------------------------------+
+---+ third_br +---+ forth_br
| |
| vlan30 | vlan30
| |
| |
| third_if | forth_if
+---+ +----+
+---+ +----+
测试1:从接口second_br进入br0数据包被加上tag20标签交给了table2处理 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24root@controller-VirtualBox:~# ovs-appctl ofproto/trace br0 in_port=2
Bridge: br0
Flow: in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Rule: table=0 cookie=0 priority=0
OpenFlow actions=resubmit(,1)
Resubmitted flow: in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
Resubmitted odp: drop
Resubmitted megaflow: recirc_id=0,in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Rule: table=1 cookie=0 priority=99,in_port=2,vlan_tci=0x0000
OpenFlow actions=mod_vlan_vid:20,resubmit(,2)
Resubmitted flow: in_port=2,dl_vlan=20,dl_vlan_pcp=0,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
Resubmitted odp: drop
Resubmitted megaflow: recirc_id=0,in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Rule: table=254 cookie=0 priority=0,reg0=0x2
OpenFlow actions=drop
Final flow: in_port=2,dl_vlan=20,dl_vlan_pcp=0,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Megaflow: recirc_id=0,in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Datapath actions: drop
测试2:tag 5的数据包从second_br进入br0,命中默认丢包策略1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17root@controller-VirtualBox:~# ovs-appctl ofproto/trace br0 in_port=2,vlan_tci=5
Bridge: br0
Flow: in_port=2,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Rule: table=0 cookie=0 priority=0
OpenFlow actions=resubmit(,1)
Resubmitted flow: in_port=2,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
Resubmitted odp: drop
Resubmitted megaflow: recirc_id=0,in_port=2,vlan_tci=0x0001/0x0001,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Rule: table=1 cookie=0 priority=0
OpenFlow actions=drop
Final flow: unchanged
Megaflow: recirc_id=0,in_port=2,vlan_tci=0x0001/0x1001,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Datapath actions: drop
flow table 2 策略(让br0具有mac学习能力)
学习port-mac-vlan tag 数据表将学习结果放到table10,学习后交给table3继续处理
1 | ovs-ofctl add-flow br0 "table=2 actions=learn(table=10, NXM_OF_VLAN_TCI[0..11], NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15]), resubmit(,3)" |
- learn表示这是一个学习的action
- table 10,这是一个MAC learning table,学习的结果会放在这个table中。
- NXM_OF_VLAN_TCI这个是VLAN Tag,在MAC Learning * table中,每一个entry都是仅仅对某一个VLAN来说的,不同VLAN的learning table是分开的。在学习的结果的entry中,会标出这个entry是对于哪个VLAN的。
- NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]这个的意思是当前包里面的MAC Source Address会被放在学习结果的entry里面的dl_dst里面。这是因为每个switch都是通过Ingress包来学习,某个MAC从某个port进来,switch就应该记住以后发往这个MAC的包要从这个port出去,因而MAC source address就被放在了Mac destination address里面,因为这是为发送用的。
- NXM_OF_IN_PORT[]->NXM_NX_REG0将portf放入register.
- 一般对于学习的entry还需要有hard_timeout,这是的每个学习结果都会expire,需要重新学习。
table2 转发表项学习测试
产生从接口first_br进入br0 vlan20的数据包
1 | ovs-appctl ofproto/trace br0 in_port=1,vlan_tci=20,dl_src=50:00:00:00:00:01 -generate |
结果:执行 ovs-ofctl dump-flows br0时候学习到了一个table10表项1
cookie=0x0, duration=3.235s, table=10, n_packets=0, n_bytes=0, idle_age=3, vlan_tci=0x0014/0x0fff,dl_dst=50:00:00:00:00:01 actions=load:0x1->NXM_NX_REG0[0..15]
table 3策略(把table2学习到的转发策略运用起来)
针对于要发送的数据包,根据学习结果table10进行转发,不用每次flood
下面命令含义是:先到table10查找,如果找不到相应策略再交给table4处理1
ovs-ofctl add-flow br0 "table=3 priority=50 actions=resubmit(,10), resubmit(,4)"
查找学习表项排除多播和广播
如果数据包为多播火灾 广播,就不需要查找table10,直接交给table4处理1
ovs-ofctl add-flow br0 "table=3 priority=99 dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,4)"
table 4策略(让vlan和trunk隔离工作起来)
对于接口first_br,是trunk port,如果数据包携带tag,就让其带着从改接口出去
1 | ovs-ofctl add-flow br0 "table=4 reg0=1 actions=1" |
对于接口234,发出时候需要去除vlan标签
1 | ovs-ofctl add-flows br0 - <<'EOF' |
对于broadcast,增加策略让其在一个广播域发送数据包
1 | ovs-ofctl add-flows br0 - <<'EOF' |
所以对于register = 0的,也即是broadcast的,属于vlan 20的,则从port 1, 2出去,属于vlan 30的,则从port 1, 3, 4出去。
table4 广播隔离测试
从first_br来的tag=30数据包广播
1 | ovs-appctl ofproto/trace br0 in_port=1,dl_dst=ff:ff:ff:ff:ff:ff,dl_vlan=30 |
从接口third_br(in_port 3)进入的数据包被加上tag30标签,转发给接口1接口4
1 | ovs-appctl ofproto/trace br0 in_port=3,dl_dst=ff:ff:ff:ff:ff:ff |
首次产生的数据包,因同属于tag30会被发送给接口3和接口4
1 | ovs-appctl ofproto/trace br0 in_port=1,dl_vlan=30,dl_src=10:00:00:00:00:01,dl_dst=20:00:00:00:00:01 -generate |
学习了20:00:00:00:00:01 in_port=1 tag 30 到table10
数据包回复时候,仅仅从接口1发出去
1 | ovs-appctl ofproto/trace br0 in_port=4,dl_src=20:00:00:00:00:01,dl_dst=10:00:00:00:00:01 -generate |
根据上述表项进行数据包转发,不需要flood数据包之需要发给接口1
并且学习到了20:00:00:00:00:01 in_port=4 tag=30
数据包包回复时候,仅仅发给接口4
1 | ovs-appctl ofproto/trace br0 in_port=1,dl_vlan=30,dl_src=10:00:00:00:00:01,dl_dst=20:00:00:00:00:01 -generate |
根据上述表项进行数据包转发,不需要flood数据包之需要发给接口4