openvSwitch flow

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 的参数,采用如下的格式:字段=值。如果有多个字段,可以用逗号或者空格分开
flow

流表执行的动作

流表可以有多个执行动作,是从左向右以此执行,常用动作如下:

  • 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 指明要发送给的控制器id

  • mod_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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
     +----+                          +----+
| | first_if | | second_if
+----+ +----+
| |
| |
| |
| |
| first_br | second_br
+---+ +---+
+-------------------------------------------------------+
| +---+ +---+ |
| |
| |
| br0 |
| |
| |
| +---+ +---+ |
+-------------------------------------------------------+
+---+ third_br +---+ forth_br
| |
| |
| |
| third_if | forth_if
+---+ +----+
+---+ +----+

实验拓扑基础环境实现脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ovs-vsctl add-br br0
ip link add first_br type veth peer name first
ip link add second_br type veth peer name second_if
ip link add third_br type veth peer name third_if
ip link add forth_br type veth peer name forth_if


ovs-vsctl add-port br0 first_br -- set Interface first_br ofport_request=1
ovs-vsctl add-port br0 second_br -- set Interface second_br ofport_request=2
ovs-vsctl add-port br0 third_br -- set Interface third_br ofport_request=3
ovs-vsctl add-port br0 forth_br -- set Interface forth_br ofport_request=4

ip link set first_if up
ip link set first_br up
ip link set second_br up
ip link set second_if up
ip link set third_if up
ip link set third_br up
ip link set forth_br up
ip link set forth_if up

脚本执行完成后,查看flow策略

1
2
3
root@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
2
3
4
5
6
7
8
9
10
root@controller-VirtualBox:~# ovs-appctl ofproto/trace br0 in_port=1,dl_dst=01:80:c2:00:00:05
Bridge: br0
Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=01:80:c2:00:00:05,dl_type=0x0000

Rule: table=0 cookie=0 dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0
OpenFlow actions=drop

Final flow: unchanged
Megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
Datapath actions: drop
  • 命中table=0 cookie=0 priority=0 OpenFlow actions=resubmit(,1)
1
2
3
4
5
6
root@controller-VirtualBox:~# ovs-appctl ofproto/trace br0 in_port=1,dl_dst=01:80:c2:00:00:10
Bridge: br0
Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=01:80:c2:00:00:10,dl_type=0x0000

Rule: table=0 cookie=0 priority=0
OpenFlow actions=resubmit(,1)

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
12
root@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
2
3
4
5
ovs-ofctl add-flows br0 - <<'EOF' 
table=1, priority=99, in_port=2, vlan_tci=0, actions=mod_vlan_vid:20, resubmit(,2)
table=1, priority=99, in_port=3, vlan_tci=0, actions=mod_vlan_vid:30, resubmit(,2)
table=1, priority=99, in_port=4, vlan_tci=0, actions=mod_vlan_vid:30, resubmit(,2)
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
24
root@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
17
root@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
2
3
4
5
ovs-ofctl add-flows br0 - <<'EOF'   
table=4 reg0=2 actions=strip_vlan,2
table=4 reg0=3 actions=strip_vlan,3
table=4 reg0=4 actions=strip_vlan,4
EOF

对于broadcast,增加策略让其在一个广播域发送数据包

1
2
3
4
5
ovs-ofctl add-flows br0 - <<'EOF'   
table=4 reg0=0 priority=99 dl_vlan=20 actions=1,strip_vlan,2
table=4 reg0=0 priority=99 dl_vlan=30 actions=1,strip_vlan,3,4
table=4 reg0=0 priority=50 actions=1
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