Open vSwitch 是一个用C语言开发的多层虚拟交换机。
内核模块实现了多个“数据路径”(类似网桥),每个都可以有多个“vports”(类似网桥的端口)。每个数据路径也通过关联流表(flow table)来设置操作,而这些流表中的流都是用户空间在报文头和元数据的基础上映射的关键信息,一般的操作都是将数据包转发到另一个 vport。当一个数据包到达一个vport,内核模块所作的处理是提取其流的关键信息并在流表中查找这些关键信息。当有一个匹配的流时,它执行对应的操作。如果没有匹配,它会将数据包发送到用户空间的处理队列中(作为处理的一部分,用户空间可能会设置一个流用于以后碰到相同类型的数据包可以在内核中执行操作)
OVS 架构由内核态的 Datapath 和用户态的 vswitchd、ovsdb 组成:
管理工具:
OVS 创建网桥,绑定物理网卡后,数据流从物理网卡端口接收包后,在内核态由OVS的vPort进入OVS中,根据数据包Key值进行FlowTable流表匹配,成功则执行流表Action后续流程,失败则Upcall由vswitchd进程处理
OVS集群组网拓扑图:
Bridge: 网桥,即交换机(Switch),一台主机中可创建一个或多个Bridge。Bridge可根据一定的规则,把某个端口接收到的数据报文转发到另一个或多个端口上,也可以修改或者丢弃数据报文
Port: 端口,即交换机上的插口。有以下几种类型:
Interface: 网卡,可以是虚拟的(TUN/TAP)或物理的都可以。
Controller:控制器,OVS可接收一个或多个OpenFlow控制器的管理,主要功能为下发流表来控制转发规则
Flow:流表,OVS进行数据转发的核心功能,定义了端口之间的转发数据报文的规则。每条流表规则可分为匹配和动作两部分,“匹配”决定哪些数据将被处理;动作决定了匹配到的数据报文该如何处理
ovs-vsctl add-br br0
ovs-vsctl list-br
ovs-vsctl del-br br0
ovs-vsctl br-exists br0
ovs-vsctl add-port br0 ens38 # 物理网卡
ovs-vsctl del-port br0 ens38
ovs-vsctl add-port br0 p0 -- set interface p0 type=internal
# 设置IP地址
ip link set p0 up
ip addr add 192.168.80.10/24 dev p0
# 设置VLAN tag
ovs-vsctl set port p0 tag=100
ovs-vsctl remove port p0 tag 100
# 设置允许通过的VLAN tag
ovs-vsctl set port p0 trunks=100,200
ovs-vsctl remove port p0 trunks 100,200
ovs-vsctl add-br br0
ovs-vsctl add-br br1
ovs-vsctl add-port br0 patch0 -- set interface patch0 type=patch options:peer=patch1
ovs-vsctl add-port br1 patch1 -- set interface patch1 type=patch options:peer=patch0
# 192.168.3.103
ovs-vsctl add-br br0
ovs-vsctl add-port br0 vxlan01 -- set interface vxlan01 type=vxlan options:remote_ip=192.168.3.104
# 192.168.3.104
ovs-vsctl add-br br0
ovs-vsctl add-port br0 vxlan01 -- set interface vxlan01 type=vxlan options:remote_ip=192.168.3.103
# 设置VLAN mode: trunk|access|native-tagged|native-untagged
ovs-vsctl set port p0 vlan_mode=trunk
ovs-vsctl get port p0 vlan_mode
ovs-vsctl remove port p0 vlan_mode trunk
# 查看Port的属性
ovs-vsctl list interface p0
# 网桥下的所有端口
ovs-vsctl list-ports br0
# 端口所属的网桥
ovs-vsctl port-to-br p0
# ovs网络状态
ovs-vsctl show
# 设置控制器
ovs-vsctl set-controller br0 tcp:ip:6633
ovs-vsctl del-controller br0
# 设置支持OpenFlow Version 1.3
ovs-vsctl set bridge br0 protocols=OpenFlow13
# 删除OpenFlow支持设置
ovs-vsctl clear bridge br0 protocols
# 查看网桥上所有交换机端口的状态
ovs-ofctl dump-ports br0
# 查看网桥上所有的流规则
ovs-ofctl dump-flows br0
# 查看ovs的版本:
ovs-ofctl -V
ovs-vsctl add-br br0
# 添加内部端口
ovs-vsctl add-port br0 vnet0 -- set interface vnet0 type=internal
ovs-vsctl add-port br0 vnet1 -- set interface vnet1 type=internal
ovs-vsctl add-port br0 vnet2 -- set interface vnet2 type=internal
# 添加网络命名空间
ip netns add ns0
ip netns add ns1
ip netns add ns2
# 移到端口到网络命令空间
ip link set vnet0 netns ns0
ip link set vnet1 netns ns1
ip link set vnet2 netns ns2
# 启用端口并配置IP
ip netns exec ns0 ip link set lo up
ip netns exec ns0 ip link set vnet0 up
ip netns exec ns0 ip addr add 10.0.0.1/24 dev vnet0
ip netns exec ns0 ip addr show
ip netns exec ns1 ip link set lo up
ip netns exec ns1 ip link set vnet1 up
ip netns exec ns1 ip addr add 10.0.0.2/24 dev vnet1
ip netns exec ns1 ip addr show
ip netns exec ns2 ip link set lo up
ip netns exec ns2 ip link set vnet2 up
ip netns exec ns2 ip addr add 10.0.0.3/24 dev vnet2
ip netns exec ns2 ip addr show
# 连通性验证
ip netns exec ns0 ping 10.0.0.2 # ok
ip netns exec ns0 ping 10.0.0.3 # ok
# 设置VLAN
ovs-vsctl set port vnet0 tag=100
ovs-vsctl set port vnet1 tag=100
ovs-vsctl set port vnet2 tag=200
# 连通性验证
ip netns exec ns0 ping 10.0.0.2 # ok
ip netns exec ns0 ping 10.0.0.3 # unavailable
未配置VLAN:
#### 主机A ####################################################
ovs-vsctl add-br br-int
# 添加物理网卡
ovs-vsctl add-port br-int ens38
ip link set ens38 up # 非常必要,否则无法跨节点通信
# 添加内部端口
ovs-vsctl add-port br-int vnet0 -- set interface vnet0 type=internal
ovs-vsctl add-port br-int vnet1 -- set interface vnet1 type=internal
# 添加网络命名空间
ip netns add ns0
ip netns add ns1
# 移到端口到网络命令空间
ip link set vnet0 netns ns0
ip link set vnet1 netns ns1
# 启用端口并配置IP
ip netns exec ns0 ip link set lo up
ip netns exec ns0 ip link set vnet0 up
ip netns exec ns0 ip addr add 10.0.0.1/24 dev vnet0
ip netns exec ns0 ip addr show
ip netns exec ns1 ip link set lo up
ip netns exec ns1 ip link set vnet1 up
ip netns exec ns1 ip addr add 10.0.0.2/24 dev vnet1
ip netns exec ns1 ip addr show
# 网桥详情
ovs-vsctl show
f96a27d4-c91d-43ff-858b-fd559fe6b771
Bridge br-int
Port ens38
Interface ens38
Port vnet1
Interface vnet1
type: internal
Port vnet0
Interface vnet0
type: internal
Port br-int
Interface br-int
type: internal
ovs_version: "2.13.3"
#### 主机B ####################################################
ovs-vsctl add-br br-int
# 添加物理网卡
ovs-vsctl add-port br-int ens38
ip link set ens38 up # 非常必要,否则无法跨节点通信
# 添加内部端口
ovs-vsctl add-port br-int vnet0 -- set interface vnet0 type=internal
ovs-vsctl add-port br-int vnet1 -- set interface vnet1 type=internal
# 添加网络命名空间
ip netns add ns0
ip netns add ns1
# 移到端口到网络命令空间
ip link set vnet0 netns ns0
ip link set vnet1 netns ns1
# 启用端口并配置IP
ip netns exec ns0 ip link set lo up
ip netns exec ns0 ip link set vnet0 up
ip netns exec ns0 ip addr add 10.0.0.3/24 dev vnet0
ip netns exec ns0 ip addr show
ip netns exec ns1 ip link set lo up
ip netns exec ns1 ip link set vnet1 up
ip netns exec ns1 ip addr add 10.0.0.4/24 dev vnet1
ip netns exec ns1 ip addr show
# 网桥详情
ovs-vsctl show
验证:
#### 主机A ####################################################
ip netns exec ns0 ping 10.0.0.1 # ok
ip netns exec ns0 ping 10.0.0.2 # ok
ip netns exec ns0 ping 10.0.0.3 # ok
ip netns exec ns0 ping 10.0.0.4 # ok
#### 主机B ####################################################
ip netns exec ns1 ping 10.0.0.1 # ok
ip netns exec ns1 ping 10.0.0.2 # ok
ip netns exec ns1 ping 10.0.0.3 # ok
ip netns exec ns1 ping 10.0.0.4 # ok
配置VLAN:
#### 主机A ####################################################
ovs-vsctl set port vnet0 tag=100
ovs-vsctl set port vnet1 tag=200
#### 主机B ####################################################
ovs-vsctl set port vnet0 tag=100
ovs-vsctl set port vnet1 tag=200
验证:
#### 主机A ####################################################
ip netns exec ns0 ping 10.0.0.1 # ok
ip netns exec ns0 ping 10.0.0.2 # unavailable
ip netns exec ns0 ping 10.0.0.3 # ok
ip netns exec ns0 ping 10.0.0.4 # unavailable
#### 主机B ####################################################
ip netns exec ns1 ping 10.0.0.1 # unavailable
ip netns exec ns1 ping 10.0.0.2 # ok
ip netns exec ns1 ping 10.0.0.3 # unavailable
ip netns exec ns1 ping 10.0.0.4 # ok
镜像源:
镜像目的:
# 新增端口镜像
ovs-vsctl -- set Bridge <bridge_name> mirrors=@m \
-- --id=@<port0> get Port <port0> \
-- --id=@<port1> get Port <port1> \
-- --id=@m create Mirror name=<mirror_name> select-dst-port=@<port0> select-src-port=@<port0> output-port=@<port1>
# 删除端口镜像
ovs-vsctl remove Bridge <bridge-name> mirrors <mirror-id>
# 获取端口的ID
ovs-vsctl get port <port_name> _uuid
# 在原端口镜像的基础上增加镜像源
ovs-vsctl add Mirror <mirror-name> select_src_port <port-id>
ovs-vsctl add Mirror <mirror-name> select_dst_port <port-id>
# 在原端口镜像的基础上删除镜像源
ovs-vsctl remove Mirror <mirror-name> select_src_port <port-id>
ovs-vsctl remove Mirror <mirror-name> select_dst_port <port-id>
# 清空端口镜像
ovs-vsctl clear Mirror
# 查看端口镜像
ovs-vsctl list Mirror
# 关闭端口的MAC地址学习
ovs-ofctl mod-port <bridge-name> <port-name> NO-FLOOD
ovs-vsctl add-br br-int
# 添加内部端口
ovs-vsctl add-port br-int vnet0 -- set interface vnet0 type=internal
ovs-vsctl add-port br-int vnet1 -- set interface vnet1 type=internal
ovs-vsctl add-port br-int vnet2 -- set interface vnet2 type=internal
# 添加网络空间
ip netns add ns0
ip netns add ns1
ip netns add ns2
# 内部端口移到网络空间
ip link set vnet0 netns ns0
ip link set vnet1 netns ns1
ip link set vnet2 netns ns2
# 启用端口、配置IP
ip netns exec ns0 ip link set lo up
ip netns exec ns0 ip link set vnet0 up
ip netns exec ns0 ip addr add 10.0.0.1/24 dev vnet0
ip netns exec ns0 ip addr show
ip netns exec ns1 ip link set lo up
ip netns exec ns1 ip link set vnet1 up
ip netns exec ns1 ip addr add 10.0.0.2/24 dev vnet1
ip netns exec ns1 ip addr show
ip netns exec ns2 ip link set lo up
ip netns exec ns2 ip link set vnet2 up
ip netns exec ns2 ip addr add 10.0.0.3/24 dev vnet2
ip netns exec ns2 ip addr show
# 增加端口镜像
ovs-vsctl set bridge br-int mirrors=@m \
-- --id=@vnet1 get port vnet1 \
-- --id=@vnet2 get port vnet2 \
-- --id=@m create mirror name=mirror_test select-dst-port=@vnet1 select-src-port=@vnet1 output-port=@vnet2
将流量发送到vnet1:
ip netns exec ns0 ping 10.0.0.2
监控 vnet2 的流量:
ip netns exec ns2 tcpdump -i vnet2
15:10:35.785945 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 17311, seq 25, length 64
15:10:35.785978 IP 10.0.0.2 > 10.0.0.1: ICMP echo reply, id 17311, seq 25, length 64
15:10:36.809925 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 17311, seq 26, length 64
15:10:36.809938 IP 10.0.0.2 > 10.0.0.1: ICMP echo reply, id 17311, seq 26, length 64
15:10:37.834173 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 17311, seq 27, length 64
15:10:37.834196 IP 10.0.0.2 > 10.0.0.1: ICMP echo reply, id 17311, seq 27, length 64
15:10:38.858455 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 17311, seq 28, length 64
15:10:38.858477 IP 10.0.0.2 > 10.0.0.1: ICMP echo reply, id 17311, seq 28, length 64
OVS流表就像是“大腿”一样接受来自“大脑”的指令,决定要向哪个方向前进
ovs-ofctl dump-flows br0
ovs-ofctl add-flow "CONDITION, action=ACT1,ACT2..."
ovs-ofctl add-flows "CONDITION, action=ACT1,ACT2..."
ovs-ofctl mod-flows "CONDITION, action=ACT1,ACT2..."
# 清空流表
ovs-ofctl del-flows br0
# 删除特定流表规则
ovs-ofctl del-flows br0 xx
主要分四部分:
key | value | comment |
---|---|---|
in_port | port | 流量进入的端口编号或名称,示例 in_port=br0 |
table | number | 规则保存的流表编号,0~254, 默认0 |
dl, data link
key | value | comment |
---|---|---|
dl_type | ethertype | 以太网类型,10~65535, 也可以使用别名 ip/arp/ipv6/arp |
dl_vlan | tag | Vlan Tag, 0~4095 |
dl_vlan_pcp | priority | 优先级, 0~7 |
dl_src | mac | 源mac地址 |
dl_dst | mac | 目的mac地址 |
key | value | comment |
---|---|---|
nw_src | ip/mask | |
nw_dst | ip/mask | |
nw_proto | proto | |
ipproto | proto | |
nw_tos | tos | 匹配IP ToS / DSCP或IPv6流量类别字段tos, 0~255 |
ip_dscp | dscp | 匹配IP ToS / DSCP或IPv6流量类字段dscp, 0~63 |
nw_ecn | ecn | 匹配IP ToS / DSCP或IPv6流量类字段dscp, 0~63 |
ip_ecn | ecn | 匹配IP ToS或IPv6流量类别字段中的ecn位, 0~3 |
nw_ttl | ttl | 匹配IP TTL或IPv6跃点限制值ttl, 0~255 |
key | value | comment |
---|---|---|
tcp_src | port, port/mask | |
tcp_dst | port port/mask | |
tcp_flags | flags/mask | 0:fin 查找不再有来自发送方的数据。 1:syn 同步同步序列号。 2:rst 重置连接。 3:psh 推送功能。 4:ack 确认字段有效。 5:urg 紧急指针字段有效。 6:ece ECN回显。 7:cer 减少拥塞窗口。 8:ns 现时总和 9-11:保留。 12-15:不处理,必须为零。 |
icmp_type | type | |
ip | dl_type=0x0800 | |
icmp | 等同于dl_type=0x0800,nw_proto=1 |
|
tcp | 等同于dl_type=0x0800,nw_proto=6 |
|
udp | 等同于dl_type=0x0800,nw_proto=17 |
|
arp | 等同于dl_type=0x0806 |
action | comment |
---|---|
output:port | 将数据包输出到OpenFlow端口号port。如果port是数据包的输入端口,则不输出数据包。 |
local | 在与本地网桥名称相同的网络设备对应的``本地端口’'上输出数据包。 |
in_port | 在接收数据包的端口上输出数据包 |
drop | 丢弃数据包,因此不会进行进一步的处理或转发。如果使用丢弃动作,则不能指定其他动作 |
mod_dl_src:mac | 将源以太网地址设置为mac |
mod_nw_src:ip | 将IPv4源地址设置为ip |
参考资料:https://www.openvswitch.org/support/dist-docs-2.5/ovs-ofctl.8.txt