基于 Open vSwitch 的 OpenFlow 实践

目录

文章目录

  • 目录
  • 前文列表
  • Open vSwitch 基本概念
  • Open vSwitch 与 OpenFlow 的关系
  • 通过 Open vSwitch 实践 OpenFlow
    • 屏蔽数据包
    • 重定向数据包
    • 修改数据包源 IP 地址
    • 修改数据包 VLAN tag

前文列表

《OpenFlow/SDN 的缘起与发展》
《OpenFlow Switch 1.3 规范》
《OpenvSwitch/OpenFlow 架构解析与实践案例》

Open vSwitch 基本概念

Bridge:在 Linux 的语义中代表一个虚拟的以太网交换机(vSwitch)。

Port:Bridge 的端口,每个 Port 都隶属于一个 Bridge。

Interface:连接到 Port 的网络接口设备(e.g. Tap、eth0)。通常情况下,Port 和 Interface 是一对一关系,为 Port 配置 bond 模式后,Port:Interface 是 1:N 的关系。

Controller:OpenFlow 控制器,OvS 作为 OpenFlow 交换机可以同时接受一个或多个 OpenFlow Controller 的管理。

Datapath:在 OpenFlow 的语义中,Datapath 就是一个 OpenFlow 交换机。负责执行数据交换,把从接收 Port 收到的数据包在流表中进行匹配,并执行匹配到的动作。

Flow Table:流表,Datapath 与流表关联,流表记录了网络包的匹配域、计数器和动作集。OpenFlow Controller 通过设定 OvS 的流表来对 SDN 网络进行 “编程”。

Open vSwitch 与 OpenFlow 的关系

Open vSwitch(简称 OvS)是遵守 OpenFlow Switch Specification 的 OpenFlow 交换机软件实现。OpenFlow 协议是用于管理 OpenFlow Switch 流表的协议,ovs-ofctl 就是 OvS 提供的 OpenFlow 流表配置命令行工具。在没有配置 OpenFlow Controller 的场景中,用户可以直接使用 ovs-ofctl 命令与 OvS 连接 OpenFlow 通道,并以此创建、修改或删除 OvS 中的流表项,同时对 OvS 的运行状况进行动态监控。

基于 Open vSwitch 的 OpenFlow 实践_第1张图片
在 OvS 中,流表项作为 ovs-ofctl 指令的参数,采用 字段=值 的格式,如果有多个字段,可以是用逗号或者空格分开。e.g.

ovs-ofctl add-flow ovs-switch "table=0, dl_src=01:00:00:00:00:00/01:00:00:00:00:00, actions=drop"

通过 Open vSwitch 实践 OpenFlow

查看 OvS 服务进程:

[root@ovs ~]# ps -ea | grep ovs
 1295 ?        00:00:00 ovsdb-server
 1310 ?        00:00:00 ovs-vswitchd

查看 OvS 版本:

[root@ovs ~]# ovs-appctl --version
ovs-appctl (Open vSwitch) 2.0.0
Compiled Apr 19 2018 17:57:34

查看 OvS 支持的 OpenFlow 版本:

[root@ovs ~]# ovs-ofctl --version
ovs-ofctl (Open vSwitch) 2.0.0
Compiled Apr 19 2018 17:57:34
OpenFlow versions 0x1:0x4

新建一个 OvS Switch:

[root@ovs ~]# ovs-vsctl add-br ovs-switch

[root@ovs ~]# ovs-vsctl show
367a97be-5b4f-40e2-8630-e64f67172fd2
    Bridge ovs-switch
        Port ovs-switch
            Interface ovs-switch
                type: internal
    ovs_version: "2.0.0"

[root@ovs ~]# ip a
...
3: ovs-system:  mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 3a:3f:8b:8c:5d:31 brd ff:ff:ff:ff:ff:ff

# Port ovs-switch 的 Interface 虚拟网络设备
4: ovs-switch:  mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether 16:50:76:b2:22:46 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::f018:ff:fed7:bf2a/64 scope link
       valid_lft forever preferred_lft forever

NOTE:OvS Switch 默认会有一个 “internal” 类型的同名 Port,相当于物理交换机的管理端口。

创建 Port p0,并设置 p0 的 OpenFlow 端口编号为 100。OpenFlow 端口编号常被作为流表项的匹配字段,如果没有显式指定 OpenFlow 端口编号,OvS 会随机指定。

[root@ovs ~]# ovs-vsctl add-port ovs-switch p0 -- set Interface p0 ofport_request=100

[root@ovs ~]# ovs-vsctl show
367a97be-5b4f-40e2-8630-e64f67172fd2
    Bridge ovs-switch
        Port ovs-switch
            Interface ovs-switch
                type: internal
        Port "p0"
            Interface "p0"
    ovs_version: "2.0.0"

NOTE:除了在创建 Port 的时候指定虚拟接口设备 p0,也可以指定一个物理接口设备(e.g. eth0)。

设定 p0 的 Interface 类型为 “internal”:

[root@ovs ~]# ovs-vsctl set Interface p0 type=internal

[root@ovs ~]# ip a
...
5: p0:  mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether 5a:d7:49:85:d9:da brd ff:ff:ff:ff:ff:ff
    inet6 fe80::58d7:49ff:fe85:d9da/64 scope link
       valid_lft forever preferred_lft forever

NOTE:Internal 类型是 OvS 内部创建的虚拟网卡接口,每创建一个 Port,OvS 会自动在 Linux 上创建一个同名接口设备挂载到新创建的 Port 上。同时可以为这个虚拟网络设备配置 IP 地址,进行数据监听等。

为了避免 OvS Interface 的 IP 地址与 HostOS 本地的 IP 地址冲突,可以创建一个 Network Namespace ns0,把 p0 的 Interface 移入 ns0 中,并配置 IP 地址为 192.168.1.100。

# 新建 ns0,初始 ns0 只有 lo 设备
[root@ovs ~]# ip netns add ns0
[root@ovs ~]# ip netns exec ns0 ip l
1: lo:  mtu 65536 qdisc noop state DOWN mode DEFAULT qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

# 将 p0 移入 ns0 后,p0  被隔离在 ns0,HostOS 看不见 p0 Interface 设备
[root@ovs ~]# ip link set p0 netns ns0
[root@ovs ~]# ip netns exec ns0 ip l
1: lo:  mtu 65536 qdisc noop state DOWN mode DEFAULT qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: p0:  mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether 5a:d7:49:85:d9:da brd ff:ff:ff:ff:ff:ff
[root@ovs ~]# ip l
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0:  mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether fa:16:3e:c4:f4:7f brd ff:ff:ff:ff:ff:ff
3: ovs-system:  mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether 3a:3f:8b:8c:5d:31 brd ff:ff:ff:ff:ff:ff
4: ovs-switch:  mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1000
    link/ether 16:50:76:b2:22:46 brd ff:ff:ff:ff:ff:ff

# 为 ns0 内的 p0 设定 IP 地址和开启混杂模式,让所有 MAC 地址的二层帧都能通过
[root@ovs ~]# ip netns exec ns0 ip addr add 192.168.1.100/24 dev p0
[root@ovs ~]# ip netns exec ns0 ifconfig p0 promisc up
[root@ovs ~]# ip netns exec ns0 ip a
1: lo:  mtu 65536 qdisc noop state DOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: p0:  mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether 5a:d7:49:85:d9:da brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 scope global p0
       valid_lft forever preferred_lft forever
    inet6 fe80::58d7:49ff:fe85:d9da/64 scope link
       valid_lft forever preferred_lft forever

使用同样的方法创建 p1、p2,p0-2 的 IP/MAC 地址分别为:

  • p0
    • Network Namespace: ns0
    • IP: 192.168.1.100/24
    • MAC: 5a:d7:49:85:d9:da
    • OpenFlow Port Number: 100
  • p1
    • Network Namespace: ns1
    • IP: 192.168.1.101/24
    • MAC: 62:f0:3e:b6:7d:6f
    • OpenFlow Port Number: 101
  • p2
    • Network Namespace: ns2
    • IP: 192.168.1.102/24
    • MAC: 3e:3f:34:6b:0a:3d
    • OpenFlow Port Number: 102
[root@ovs ~]# ovs-vsctl show
367a97be-5b4f-40e2-8630-e64f67172fd2
    Bridge ovs-switch
        Port "p2"
            Interface "p2"
                type: internal
        Port ovs-switch
            Interface ovs-switch
                type: internal
        Port "p0"
            Interface "p0"
                type: internal
        Port "p1"
            Interface "p1"
                type: internal
    ovs_version: "2.0.0"

# 查看 OvS Switch 的详细端口信息
[root@ovs ~]# ovs-ofctl show ovs-switch
# OpenFlow Features 响应消息,包含:
#     Datapath 的唯一标示 ID
#     Datapath 支持的流表数量
#     Datapath 可以缓存数据包的最大数量
OFPT_FEATURES_REPLY (xid=0x2): dpid:0000165076b22246
n_tables:254, n_buffers:256
#     Datapath 支持的容量,即功能
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
#     Datapath 支持的动作
actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
#     Datapath 包含的 Ports 及其编号,是一个可变的 ofp_phy_port 结构体数组类型
 100(p0): addr:00:00:00:00:00:00
     # 配置为 Down,即没有手动配置为 UP
     config:     PORT_DOWN
     # 状态为 Down
     state:      LINK_DOWN
     # 数据传输速率
     speed: 0 Mbps now, 0 Mbps max
 101(p1): addr:00:00:00:00:00:00
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
 102(p2): addr:00:00:00:00:00:00
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
 LOCAL(ovs-switch): addr:f2:18:00:d7:bf:2a
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
# GET_CONFIG 答复消息,包含 flags 和 miss_send_len 配置信息
#     flags 指定了 OpenFlow 交换机的 IP 碎片处理方法
#     miss_send_len 表示在 Table-miss 时和 Packet-In 消息中发送的数据包字节数
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0

NOTE:执行指令 ovs-ofctl show ovs-switch 就相当于 OpenFlow 控制器向 OpenFlow 交换机发送了询问功能的 Features 请求消息,OpenFlow 交换机响应了 Features 应答消息给 OpenFlow,消息体记录了 OpenFlow 交换机的功能参数。这个过程就是 OpenFlow 的 “握手”。

也可以获取指定 Port 的 OpenFlow 端口编号:

[root@ovs ~]# ovs-vsctl get Interface p0 ofport
100

查看 Datapath 信息:

# Get all
[root@ovs ~]# ovs-dpctl show
system@ovs-system:
	lookups: hit:35 missed:21 lost:0
	flows: 0
	port 0: ovs-system (internal)
	port 1: ovs-switch (internal)
	port 2: p0 (internal)
	port 3: p1 (internal)
	port 4: p2 (internal)

# Get one
[root@ovs ~]# ovs-dpctl show system@ovs-system
system@ovs-system:
	lookups: hit:35 missed:21 lost:0
	flows: 0
	port 0: ovs-system (internal)
	port 1: ovs-switch (internal)
	port 2: p0 (internal)
	port 3: p1 (internal)
	port 4: p2 (internal)

检查 p0、p1、p2 的互通性:

ip netns exec ns0 ping 192.168.1.101
ip netns exec ns0 ping 192.168.1.102

NOTE:如果想在 ns0 ping 通 p0 Interface 的 IP 地址,那么首先需要把 lo Up 起来,否则执行 ip netns exec ns0 ping 192.168.1.100 ping 不通。这是因为所有只在本机内部流转的数据包都需要经过 lo 设备的处理,而 ping 外部 IP 地址时内核协议栈直接将数据包从 NIC 送出。所以如果 lo DOWN,则无法 ping 通过本地。

[root@ovs ~]# ip a
1: lo:  mtu 65536 qdisc noop state DOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: p0:  mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether 5a:d7:49:85:d9:da brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 scope global p0
       valid_lft forever preferred_lft forever
    inet6 fe80::58d7:49ff:fe85:d9da/64 scope link
       valid_lft forever preferred_lft forever

[root@ovs ~]# ip netns exec ns0 ifconfig lo up

[root@ovs ~]# ip netns exec ns0 ip a
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
5: p0:  mtu 1500 qdisc noqueue state UNKNOWN qlen 1000
    link/ether 5a:d7:49:85:d9:da brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 scope global p0
       valid_lft forever preferred_lft forever
    inet6 fe80::58d7:49ff:fe85:d9da/64 scope link
       valid_lft forever preferred_lft forever

屏蔽数据包

查看当前 OvS Switch 的所有流表,数量应该就是 OpenFlow 控制器和 OpenFlow 交换机握手时反馈的 254 张:

root@ovs ~]# ovs-ofctl dump-tables ovs-switch
OFPST_TABLE reply (xid=0x2): 254 tables
  0: classifier: wild=0x3fffff, max=1000000, active=2
               lookup=489, matched=489
  1: table1  : wild=0x3fffff, max=1000000, active=0
               lookup=0, matched=0
...

查看当前 OvS Switch 的所有流表项:

[root@ovs ~]# ovs-ofctl dump-flows ovs-switch
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=6469.422s, table=0, n_packets=82, n_bytes=6300, idle_age=2533, priority=0 actions=NORMAL
  • cookie:一个 64bit 的整数,OpenFlow 控制器用于标识流表项,相同的 cookie 值可以用来标记是同一批或同一类规则。只对 OpenFlow 控制器有效,OpenFlow 交换机不关心该字段。
  • duration:规则创建的时长
  • table:流表编号,用来建立流表的层次关系
  • n_packets、n_bytes:匹配到这条规则的网络包数、字节数。
  • idle_age:该流表项多久没有被匹配过,单位秒。
  • hard_age:这条流表项创建、修改了多次时间,单位秒。
  • priority:优先级,当 Flow 被同一个流表中的多条流表项匹配时,选择优先级高的。
  • actions=NORMAL:正常的 L2/L3 交换机行为。

NOTE:默认情况下 OvS Switch 执行传统 L2/L3 交换机的行为

添加流表项,屏蔽所有进入 OvS 的以太网广播包:

[root@ovs ~]# ovs-ofctl add-flow ovs-switch "table=0, dl_src=01:00:00:00:00:00/01:00:00:00:00:00, actions=drop"

[root@ovs ~]# ovs-ofctl dump-flows ovs-switch
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=6603.552s, table=0, n_packets=82, n_bytes=6300, idle_age=2667, priority=0 actions=NORMAL
 cookie=0x0, duration=1.952s, table=0, n_packets=0, n_bytes=0, idle_age=1, dl_src=01:00:00:00:00:00/01:00:00:00:00:00 actions=drop
  • dl_src:以太网数据帧源 MAC 地址
  • actions=drop:流表项匹配域匹配之后对 Flow( e.g. 数据包,TCP 连接)执行的动作集,这里表示丢弃数据包

NOTEdl_src=01:00:00:00:00:00/01:00:00:00:00:00 matches all multicast (including broadcast) Ethernet packets.

添加流表项,屏蔽所有进入 OvS 的 IEEE 802.1D STP 协议广播包:

[root@ovs ~]# ovs-ofctl add-flow ovs-switch "table=0, dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0, actions=drop"

[root@ovs ~]# ovs-ofctl dump-flows ovs-switch
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=15.302s, table=0, n_packets=0, n_bytes=0, idle_age=15, dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0 actions=drop
 cookie=0x0, duration=7051.931s, table=0, n_packets=82, n_bytes=6300, idle_age=3116, priority=0 actions=NORMAL
 cookie=0x0, duration=450.331s, table=0, n_packets=0, n_bytes=0, idle_age=450, dl_src=01:00:00:00:00:00/01:00:00:00:00:00 actions=drop
  • dl_dst:以太网数据帧目的 MAC 地址

删除流表项:

[root@ovs ~]# ovs-ofctl del-flows ovs-switch "dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0"
[root@ovs ~]# ovs-ofctl del-flows ovs-switch "dl_src=01:00:00:00:00:00/01:00:00:00:00:00"

重定向数据包

基于 Open vSwitch 的 OpenFlow 实践_第2张图片

添加流表项,重定向所有 ICMP 数据包到 p2:

[root@ovs ~]# ovs-ofctl add-flow ovs-switch "idle_timeout=0, dl_type=0x0800, nw_proto=1, actions=output:102"

[root@ovs ~]# ovs-ofctl dump-flows ovs-switch
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=14.749s, table=0, n_packets=0, n_bytes=0, idle_age=14, icmp actions=output:102
 cookie=0x0, duration=7605.774s, table=0, n_packets=82, n_bytes=6300, idle_age=3670, priority=0 actions=NORMAL
  • idle_timeout:流表项空闲超时时间,从上次匹配该流表项开始计时
  • dl_type=0x0800, nw_proto=1:ICMP Packet
  • actions=output:102:匹配该流表项的 Flow 被转发至 OpenFlow 端口编号为 102 的 Port

验证结果,通过 p0 ping p1,但实际是 ICMP echo request 包被转发了到 p2:

# ns0
[root@ovs ~]# ip netns exec ns0 ping 192.168.1.101
PING 192.168.1.101 (192.168.1.101) 56(84) bytes of data.

# ns1
[root@ovs ~]# ip netns exec ns1 tcpdump -i p1 -nntve -p icmp
tcpdump: listening on p1, link-type EN10MB (Ethernet), capture size 262144 bytes

# ns2
[root@ovs ~]# ip netns exec ns2 tcpdump -i p2 -nntve -p icmp
tcpdump: listening on p2, link-type EN10MB (Ethernet), capture size 262144 bytes
5a:d7:49:85:d9:da > 62:f0:3e:b6:7d:6f, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 12532, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.100 > 192.168.1.101: ICMP echo request, id 11772, seq 5, length 64

NOTE:虽然 p2 能够接收到 p0 ping p1 的 ICMP 包,但却不会进行响应,因为 IP 地址对不上。值得注意的是,即便我们从 p0 ping p2,但 p0 依旧无法接收到 ICMP reply。这是因为上述流表包含了所有的 ICMP 类型(e.g. ICMP request、ICMP reply)。e.g.

5a:d7:49:85:d9:da > 3e:3f:34:6b:0a:3d, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 53435, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.100 > 192.168.1.102: ICMP echo request, id 11780, seq 13, length 64
3e:3f:34:6b:0a:3d > 5a:d7:49:85:d9:da, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 6503, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.102 > 192.168.1.100: ICMP echo reply, id 11780, seq 13, length 64

删除流表项:

[root@ovs ~]# ovs-ofctl del-flows ovs-switch "icmp"

修改数据包源 IP 地址

基于 Open vSwitch 的 OpenFlow 实践_第3张图片

添加流表项,修改从 p0 接收到的数据包的源 IP 地址:

[root@ovs ~]# ovs-ofctl add-flow ovs-switch "priority=1, idle_timeout=0, in_port=100, actions=mod_nw_src:9.181.137.1,normal"

[root@ovs ~]# ovs-ofctl dump-flows ovs-switch
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=3.594s, table=0, n_packets=0, n_bytes=0, idle_age=3, priority=1,in_port=100 actions=mod_nw_src:9.181.137.1,NORMAL
 cookie=0x0, duration=8661.508s, table=0, n_packets=98, n_bytes=6972, idle_age=379, priority=0 actions=NORMAL
  • in_port:OvS Switch 的输入端口,表示数据包从哪一个 Switch 端口输入
  • actions=mod_nw_src:9.181.137.1:修改与匹配域匹配的数据包的三层数据包源 IP 地址

验证结果,从 p0 ping p1,数据包进入 p0 之后源 IP 地址就会修改为 9.181.137.1 了:

# ns0
[root@ovs ~]# ip netns exec ns0 ping 192.168.1.101
PING 192.168.1.101 (192.168.1.101) 56(84) bytes of data.

# ns1
[root@ovs ~]# ip netns exec ns1 tcpdump -i p1 -nntve
tcpdump: listening on p1, link-type EN10MB (Ethernet), capture size 262144 bytes
5a:d7:49:85:d9:da > 62:f0:3e:b6:7d:6f, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 27038, offset 0, flags [DF], proto ICMP (1), length 84)
    9.181.137.1 > 192.168.1.101: ICMP echo request, id 11825, seq 1, length 64

删除流表项:

[root@ovs ~]# ovs-ofctl del-flows ovs-switch "in_port=100"

修改数据包 VLAN tag

基于 Open vSwitch 的 OpenFlow 实践_第4张图片

在该例子中我们使用 ovs-appctl ofproto/trace 指令来生成测试用的模拟数据包,以此测试 OvS 对数据包的转发。

修改 p1 的 VLAN tag 为 101,是 p1 成为 VLAN tag 101 的 Access 口:

[root@ovs ~]# ovs-vsctl show
367a97be-5b4f-40e2-8630-e64f67172fd2
    Bridge ovs-switch
        Port "p2"
            Interface "p2"
                type: internal
        Port ovs-switch
            Interface ovs-switch
                type: internal
        Port "p0"
            Interface "p0"
                type: internal
        Port "p1"
            Interface "p1"
                type: internal
    ovs_version: "2.0.0"

[root@ovs ~]# ovs-vsctl set Port p1 tag=101

[root@ovs ~]# ovs-vsctl show
367a97be-5b4f-40e2-8630-e64f67172fd2
    Bridge ovs-switch
        Port "p2"
            Interface "p2"
                type: internal
        Port ovs-switch
            Interface ovs-switch
                type: internal
        Port "p0"
            Interface "p0"
                type: internal
        Port "p1"
            tag: 101
            Interface "p1"
                type: internal
    ovs_version: "2.0.0"

现在 p0 和 p1 被 VLAN 隔离了,它们之间无法进行数据交换。在此前提下,我们尝试使用 ovs-appctl ofproto/trace 生成一个从 p0 发送到 p1 的数据包,这个数据包不包含 VLAN tag:

[root@ovs ~]# ovs-appctl ofproto/trace ovs-switch "in_port=100, dl_src=5a:d7:49:85:d9:da, dl_dst=62:f0:3e:b6:7d:6f" -generate
# 描述模拟的 Flow 信息
Flow: metadata=0,in_port=100,vlan_tci=0x0000,dl_src=5a:d7:49:85:d9:da,dl_dst=62:f0:3e:b6:7d:6f,dl_type=0x0000
# 描述匹配成功的流表项
Rule: table=0 cookie=0 priority=0
# 匹配域匹配的流表项动作
OpenFlow actions=NORMAL
# 目的 MAC 地址没被学习到,进行洪泛
no learned MAC for destination, flooding

# 总结整个处理过程
Final flow: unchanged
Relevant fields: skb_priority=0,in_port=100,vlan_tci=0x0000/0x1fff,dl_src=5a:d7:49:85:d9:da,dl_dst=62:f0:3e:b6:7d:6f,dl_type=0x0000,nw_frag=no
# 数据包被发送到 Datapath 的 1,4 号端口。注:这里的编号与 OpenFlow 端口编号不等同。
Datapath actions: 1,4

添加流表项,从 p0 输入的数据包,如果它不含任何 VLAN tag,则为数据包添加 VLAN tag 101

[root@ovs ~]# ovs-ofctl add-flow ovs-switch "priority=3, in_port=100, dl_vlan=0xffff, actions=mod_vlan_vid:101,normal"

[root@ovs ~]# ovs-ofctl dump-flows ovs-switch
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=2.448s, table=0, n_packets=0, n_bytes=0, idle_age=2, priority=3,in_port=100,vlan_tci=0x0000 actions=mod_vlan_vid:101,NORMAL
 cookie=0x0, duration=11641.822s, table=0, n_packets=101, n_bytes=7098, idle_age=985, priority=0 actions=NORMAL
  • actions=mod_vlan_vid:101,normal:打上 VLAN tag 101

再次从尝试使用 ovs-appctl ofproto/trace 生成一个从 p0 到 p1 发送不包含 VLAN tag的数据包,这个数据包在进入 p0 之后会被打上 VLAN 100 的 tag:

[root@ovs ~]# ovs-appctl ofproto/trace ovs-switch "in_port=100, dl_src=5a:d7:49:85:d9:da, dl_dst=62:f0:3e:b6:7d:6f" -generate
Flow: metadata=0,in_port=100,vlan_tci=0x0000,dl_src=5a:d7:49:85:d9:da,dl_dst=62:f0:3e:b6:7d:6f,dl_type=0x0000
Rule: table=0 cookie=0 priority=3,in_port=100,vlan_tci=0x0000
OpenFlow actions=mod_vlan_vid:101,NORMAL
forwarding to learned port

Final flow: metadata=0,in_port=100,dl_vlan=101,dl_vlan_pcp=0,dl_src=5a:d7:49:85:d9:da,dl_dst=62:f0:3e:b6:7d:6f,dl_type=0x0000
Relevant fields: skb_priority=0,in_port=100,vlan_tci=0x0000,dl_src=5a:d7:49:85:d9:da,dl_dst=62:f0:3e:b6:7d:6f,dl_type=0x0000,nw_frag=no
Datapath actions: 3

NOTE:虽然通过流表项令从 p0 进来的数据包都打上 VLAN tag 101,但并非是说 p0 就成为了一个 Access 口,p0 依旧无法和 p1 正常通信,因为 p0 不具有 VLAN access 的完整功能。

你可能感兴趣的:(基于 Open vSwitch 的 OpenFlow 实践)