目录

前文列表

《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 的运行状况进行动态监控。



在 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: <BROADCAST,MULTICAST> 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: <BROADCAST,UP,LOWER_UP> 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: <BROADCAST,UP,LOWER_UP> 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: <LOOPBACK> 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: <LOOPBACK> 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: <BROADCAST> 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: <LOOPBACK,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: <BROADCAST,MULTICAST> 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: <BROADCAST,UP,LOWER_UP> 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: <LOOPBACK> 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: <BROADCAST,PROMISC,UP,LOWER_UP> 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: <LOOPBACK> 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: <BROADCAST,PROMISC,UP,LOWER_UP> 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: <LOOPBACK,UP,LOWER_UP> 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: <BROADCAST,PROMISC,UP,LOWER_UP> 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"

重定向数据包

添加流表项,重定向所有 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 地址

添加流表项,修改从 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

在该例子中我们使用 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 实践的更多相关文章

  1. 基于Open vSwitch的OpenFlow实践

    Open vSwitch(下面简称为 OVS)是由 Nicira Networks 主导的,运行在虚拟化平台(例如 KVM,Xen)上的虚拟交换机.在虚拟化平台上,OVS 可以为动态变化的端点提供 2 ...

  2. 实验2:Open vSwitch虚拟交换机实践

    作业链接:实验2:Open vSwitch虚拟交换机实践 一.实验目的 能够对Open vSwitch进行基本操作: 能够通过命令行终端使用OVS命令操作Open vSwitch交换机,管理流表: 能 ...

  3. 学习笔记——Maven实战(四)基于Maven的持续集成实践

    Martin的<持续集成> 相信很多读者和我一样,最早接触到持续集成的概念是来自Martin的著名文章<持续集成>,该文最早发布于2000年9月,之后在2006年进行了一次修订 ...

  4. 基于AWS的自动化部署实践

    过年前,我给InfoQ写了篇文章详细介绍我们团队在过去4年基于AWS的自动化部署实践.文章包括了:为什么选择AWS.AWS上自动化部署的优势和挑战.我们的解决方案,以及和AWS DevOps方案(Op ...

  5. OVS-----CentOS7上搭建基于Open vSwitch的VxLAN隧道实验

    一.关于VXLAN VXLAN 是 Virtual eXtensible LANs 的缩写,它是对 VLAN 的一个扩展,是非常新的一个 tunnel 技术,在Open vSwitch中应用也非常多. ...

  6. 基于CMS的组件复用实践

    目前前端项目大多基于Vue.React.Angular等框架来实现,这一类框架都有一个明显的特点:基于模块化以及组件化思维.所以,开发者在使用上述框架时,实际上是在写一个一个的组件,并且组件与组件之间 ...

  7. 新浪微博基于MySQL的分布式数据库实践

    提起微博,相信大家都是很了解的.但是有谁知道微博的数据库架构是怎样的呢?在今天举行的2011数据库技术大会上,新浪首席DBA杨海潮为我们详细解读了新浪微博的数据库架构——基于MySQL的分布式数据库实 ...

  8. Maven实战(四)——基于Maven的持续集成实践

    Martin的<持续集成> 相信非常多读者和我一样.最早接触到持续集成的概念是来自Martin的著名文章<持续集成>.该文最早公布于2000年9月,之后在2006年进行了一次修 ...

  9. 聊聊基于Lucene的搜索引擎核心技术实践

    最近公司用到了ES搜索引擎,由于ES是基于Lucene的企业搜索引擎,无意间在“聊聊架构”微信公众号里发现了这篇文章,分享给大家. 请点击链接:聊聊基于Lucene的搜索引擎核心技术实践

随机推荐

  1. MySQL介绍及安装环境配置

    MySQL介绍及安装环境配置 MySQL是一种关系数据库管理系统,是一种开源软件.由瑞典MySQL AB公司开发,2008年1月16号被Sun公司收购.2009年,SUN又被Oracle收购.MySQ ...

  2. IPC之mq_sysctl.c源码解读

    // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2007 IBM Corporation * * Author: Cedric ...

  3. QTP(14)

    练习1.Flight4a 要求: a.录制Flight4a登录+退出业务流程 b.使用自定义检查结合Exist属性验证登录是否成功 c.为用户名实现参数化 用户名 Jack 正确 Rose 正确 12 ...

  4. 部署jenkins+git

    Jenkins简介 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能 安装并启动思路: 安装准备 ...

  5. CSS基础学习-8.CSS盒子模型_标准盒子&&9.CSS怪异盒子

    怪异盒模型 box-sizing:content-box;/*正常盒模型,默认值*/ box-sizing:border-box:/*怪异盒模型,固定了盒子的大小,无论是否添加内边距还是边框,盒子的大 ...

  6. 第八章 watch监听 83 名称案例-使用watch监听文本框数据的变化

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  7. Java-DatabaseConnectionPool工具类

    package org.zxjava.test; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.s ...

  8. 根据传入url请求,返回json字符串

    /** * 根据传入url请求,返回json字符串 * @param url * @return * @throws UnsupportedEncodingException */ public st ...

  9. 【51nod 1038】X^A Mod P

    题目描述 X^A mod P = B,其中P为质数.给出P和A B,求< P的所有X. 例如:P = 11,A = 3,B = 5. 3^3 Mod 11 = 5 所有数据中,解的数量不超过Sq ...

  10. 使用CSS3 will-change提高页面滚动、动画等渲染性能----------------------------引用

    Chris Ruppel当其使用background-attachment: fixed实现背景图片不随滚动条滚动而滚动效果的时候, 大家肯定会好奇,这到底施了什么魔法,可以让渲染提升如此之显著.3个 ...