其他分享
首页 > 其他分享> > Open vSwitch(OVS)介绍、编译安装与原理

Open vSwitch(OVS)介绍、编译安装与原理

作者:互联网

目录

OVS安装

OVS安装

CentOS

OVS常用命令参考

流表管理

流规则组成

Packet out (注包)

参考

OVS编译

直接源码编译安装

更新内核模块

编译RPM包

启用DPDK

编译内核模块

编译deb包

参考

OVS原理

OVS架构

主要模块职责

主要数据结构

主要流程

添加网桥

流表匹配

收包处理

upcall 消息处理

参考


OVS安装

OVS安装

CentOS

yum install centos-release-openstack-newton
yum install openvswitch
systemctl enable openvswitch
systemctl start openvswitch

如果想要安装master版本,可以使用https://copr.fedorainfracloud.org/coprs/leifmadsen/ovs-master/BUILD

wget -o /etc/yum.repos.d/ovs-master.repo https://copr.fedorainfracloud.org/coprs/leifmadsen/ovs-master/repo/epel-7/leifmadsen-ovs-master-epel-7.repo
yum install openvswitch openvswitch-ovn-*

OVS常用命令参考

如何添加bridge和port

ovs-vsctl add-br br0
ovs-vsctl del-br br0
ovs-vsctl list-br
ovs-vsctl add-port br0 eth0
ovs-vsctl set port eth0 tag=1 #vlan id
ovs-vsctl del-port br0 eth0
ovs-vsctl list-ports br0
ovs-vsctl show

给OVS端口配置IP

ovs−vsctl add−port br-ex port tag=10 −− set Interface port type=internal # default is access
ifconfig port 192.168.100.1

如何配置流镜像

ovs-vsctl -- set Bridge br-int mirrors=@m -- --id=@tap6a094914-cd get Port tap6a094914-cd -- --id=@tap73e945b4-79 get Port tap73e945b4-79 -- --id=@tapa6cd1168-a2 get Port tapa6cd1168-a2 -- --id=@m create Mirror name=mymirror select-dst-port=@tap6a094914-cd,@tap73e945b4-79 select-src-port=@tap6a094914-cd,@tap73e945b4-79 output-port=@tapa6cd1168-a2

# clear
ovs-vsctl remove Bridge br0 mirrors mymirror
ovs-vsctl clear Bridge br-int mirrors

利用mirror特性对ovs端口patch-tun抓包

ip link add name snooper0 type dummy
ip link set dev snooper0 up
ovs-vsctl add-port br-int snooper0
ovs-vsctl -- set Bridge br-int mirrors=@m  \
-- --id=@snooper0 get Port snooper0  \
-- --id=@patch-tun get Port patch-tun  \
-- --id=@m create Mirror name=mymirror select-dst-port=@patch-tun \
select-src-port=@patch-tun output-port=@snooper0

# capture
tcpdump -i snooper0

# clear
ovs-vsctl clear Bridge br-int mirrors
ip link delete dev snooper0

如何配置QOS,比如队列和限速

# egress
$ ovs-vsctl -- \
add-br br0 -- \
add-port br0 eth0 -- \
add-port br0 vif1.0 -- set interface vif1.0 ofport_request=5 -- \
add-port br0 vif2.0 -- set interface vif2.0 ofport_request=6 -- \
set port eth0 qos=@newqos -- \
--id=@newqos create qos type=linux-htb \
  other-config:max-rate=1000000000 \
  queues:123=@vif10queue \
  queues:234=@vif20queue -- \
--id=@vif10queue create queue other-config:max-rate=10000000 -- \
--id=@vif20queue create queue other-config:max-rate=20000000
$ ovs-ofctl add-flow br0 in_port=5,actions=set_queue:123,normal
$ ovs-ofctl add-flow br0 in_port=6,actions=set_queue:234,normal

# ingress
ovs-vsctl set interface vif1.0 ingress_policing_rate=10000
ovs-vsctl set interface vif1.0 ingress_policing_burst=8000

# clear
ovs-vsctl clear Port vif1.0 qos
ovs-vsctl list qos
ovs-vsctl destroy qos _uuid
ovs-vsctl list qos
ovs-vsctl destroy queue _uuid

如何配置流监控sflow

ovs-vsctl -- --id=@s create sFlow agent=vif1.0 target=\"10.0.0.1:6343\" header=128 sampling=64 polling=10  -- set Bridge br-int sflow=@s
ovs-vsctl -- clear Bridge br-int sflow

如何配置流规则

ovs-ofctl add-flow br-int idle_timeout=0,in_port=2,dl_type=0x0800,dl_src=00:88:77:66:55:44,dl_dst=11:22:33:44:55:66,nw_src=1.2.3.4,nw_dst=5.6.7.8,nw_proto=1,tp_src=1,tp_dst=2,actions=drop
ovs-ofctl del-flows br-int in_port=2 //in_port=2的所有流规则被删除
ovs-ofctl  dump-ports br-int
ovs-ofctl  dump-flows br-int
ovs-ofctl show br-int //查看端口号

如何查看OVS的配置

ovs-vsctl list/set/get/add/remove/clear/destroy table record column [VALUE]

其中,TABLE名支持bridge,controller,interface,mirror,netflow,open_vswitch,port,qos,queue,ssl,sflow

配置VXLAN/GRE

ovs-vsctl add-port br-ex port -- set interface port type=vxlan options:remote_ip=192.168.100.3
ovs−vsctl add−port br-ex port −− set Interface port type=gre options:remote_ip=192.168.100.3
ovs-vsctl set interface vxlan type=vxlan option:remote_ip=140.113.215.200 option:key=flow ofport_request=9

显示并学习MAC

ovs-appctl fdb/show br-ex

设置控制器地址

ovs-vsctl set-controller br-ex tcp:192.168.100.1:6633
ovs-vsctl get-controller br0

流表管理

流规则组成

每条流规则由一系列字段组成,分为基本字段、条件字段和动作字段三部分:

流规则中可包含通配符和简写形式,任何字段都可等于*ANY,如丢弃所有收到的数据包

ovs-ofctl add-flow xenbr0 dl_type=*,nw_src=ANY,actions=drop

简写形式为将字段组简写为协议名,目前支持的简写有iparpicmptcpudp,与流规则条件字段的对应关系如下:

dl_type=0x0800 <=>ip
dl_type=0x0806 <=>arp
dl_type=0x0800,nw_proto=1 <=> icmp
dl_type=0x0800,nw_proto=6 <=> tcp
dl_type=0x0800,nw_proto=17 <=> udp
dl_type=0x86dd. <=> ipv6
dl_type=0x86dd,nw_proto=6. <=> tcp6
dl_type=0x86dd,nw_proto=17. <=> udp6
dl_type=0x86dd,nw_proto=58. <=> icmp6

屏蔽某个IP

ovs-ofctl add-flow xenbr0 idle_timeout=0,dl_type=0x0800,nw_src=119.75.213.50,actions=drop

数据包重定向

ovs-ofctl add-flow xenbr0 idle_timeout=0,dl_type=0x0800,nw_proto=1,actions=output:4

去除VLAN tag

ovs-ofctl add-flow xenbr0 idle_timeout=0,in_port=3,actions=strip_vlan,normal

更改数据包源IP地址后转发

ovs-ofctl add-flow xenbr0 idle_timeout=0,in_port=3,actions=mod_nw_src:211.68.52.32,normal

注包

# 格式为:ovs-ofctl packet-out switch in_port actions packet
# 其中,packet为hex格式数据包
ovs-ofctl packet-out br2 none output:2 040815162342FFFFFFFFFFFF07C30000

流表常用字段

常见的操作

跟踪数据包的处理过程

ovs-appctl ofproto/trace br0 in_port=3,tcp,nw_src=10.0.0.2,tcp_dst=22

ovs-appctl ofproto/trace br-int \
 in_port=1,dl_src=00:00:00:00:00:01,\
  dl_dst=00:00:00:00:00:02 -generate

Packet out (注包)

import binascii
from scapy.all import *
a=Ether(dst="02:ac:10:ff:00:22",src="02:ac:10:ff:00:11")/IP(dst="172.16.255.22",src="172.16.255.11", ttl=10)/ICMP()
print binascii.hexlify(str(a))

ovs-ofctl packet-out br-int 5 "normal" 02AC10FF002202AC10FF001108004500001C000100000A015A9DAC10FF0BAC10FF160800F7FF00000000

参考

 

OVS编译

直接源码编译安装

export OVS_VERSION="2.6.1"
export OVS_DIR="/usr/src/ovs"
export OVS_INSTALL_DIR="/usr"
curl -sSl http://openvswitch.org/releases/openvswitch-${OVS_VERSION}.tar.gz | tar -xz && mv openvswitch-${OVS_VERSION} ${OVS_DIR}

cd ${OVS_DIR}
./boot.sh
# 如果启用DPDK,还需要加上--with-dpdk=/usr/local/share/dpdk/x86_64-native-linuxapp-gcc
./configure --prefix=${OVS_INSTALL_DIR} --localstatedir=/var --enable-ssl --with-linux=/lib/modules/$(uname -r)/build
make -j `nproc`
make install
make modules_install

更新内核模块

cat > /etc/depmod.d/openvswitch.conf << EOF
override openvswitch * extra
override vport-* * extra
EOF

depmod -a
cp debian/openvswitch-switch.init /etc/init.d/openvswitch-switch
/etc/init.d/openvswitch-switch force-reload-kmod

编译RPM包

make rpm-fedora RPMBUILD_OPT="--without check"

启用DPDK

make rpm-fedora RPMBUILD_OPT="--with dpdk --without check"

编译内核模块

make rpm-fedora-kmod

编译deb包

apt-get install build-essential fakeroot
dpkg-checkbuilddeps
# 已经编译过,需要首先clean
# fakeroot debian/rules clean
DEB_BUILD_OPTIONS='parallel=8 nocheck' fakeroot debian/rules binary

参考

 

OVS原理

OVS架构

图片来源 2015 FOSDEM - OVS Stateful Services

 

ovs的架构如上图所示,主要由内核datapath和用户空间的vswitchdovsdb组成。

图片来源 OpenvSwitch Deep Dive

主要模块职责

主要数据结构

(图片来自 csdn)

 

主要流程

注:部分转载自OVS 源码分析整理

添加网桥

  1. 键入命令ovs-vsctl add-br testBR
  2. 内核中的 openvswitch.ko 收到一个添加网桥的命令时候——即收到 OVS_DATAPATH_FAMILY通道的 OVS_DP_CMD_NEW命令。该命令绑定的回调函数为 ovs_dp_cmd_new
  3. ovs_dp_cmd_new 函数除了初始化 dp 结构外,调用 new_vport 函数来生成新的 vport
  4. new_vport 函数调用 ovs_vport_add()来尝试生成一个新的 vport
  5. ovs_vport_add()函数会检查 vport 类型(通过 vport_ops_list[]数组),并调用相关的 create()函数来生成 vport 结构
  6. 当dp是网络设备时(vport_netdev.c),最终由 ovs_vport_add()函数调用的是 netdev_create()【在 vport_ops_listovs_netdev_ops 中】
  7. netdev_create()函数最关键的一步是注册了收到网包时的回调函数
  8. err=netdev_rx_handler_register(netdev_vport->dev,netdev_frame_hook,vport);
  9. 操作是将 netdev_vport->dev 收到网包时的相关数据由 netdev_frame_hook()函数来处理,都是些辅助处理,依次调用各处理函数,在 netdev_port_receive()【这里会进行数据包的拷贝,避免损坏】进入 ovs_vport_receive()回到 vport.c,从 ovs_dp_process_receive_packet()回到 datapath.c,进行统一处理
  10. 流程:netdev_frame_hook()->netdev_port_receive->ovs_vport_receive->ovs_dp_process_received_packet()
  11. net_port_receive()首先检测是否 skb 被共享,若是则得到 packet 的拷贝。
  12. net_port_receive()其调用ovs_vport_receive(),检查包的校验和,然后交付给我们的vport通用层来处理。
 (图片来自 简书)

流表匹配

  1. flow_lookup()查找对应的流表项
  2. for 循环调用 rcu_dereference_ovs 对流表结构体中的 mask_list 成员遍历,找到对应的的 成员
  3. flow=masked_flow_lookup()遍历进行下一级 hmap查找,找到为止
  4. 进入 包含函数 ovs_flow_mask_key(&masked_key,unmasked,mask),将最开始提取的 Key 值和 mask 的 key 值进行“与”操作,结果存放在 masked_key 中,用来得到后面的 Hash 值
  5. hash=flow_hash(&masked_key,key_start,key_end)key 值的匹配字段只有部分
  6. ovs_vport_add()函数会检查 vport 类型(通过 vport_ops_list[]数组),并调用相关的 create()函数来生成 vport 结构
  7. 可见,当 dp 时网络设备时(vport_netdev.c),最终由 ovs_vport_add()函数调用的是 netdev_create()【在 vport_ops_listovs_netdev_ops 中】
  8. netdev_vport->dev 收到网包时的相关数据由 netdev_frame_hook()函数来处理,都是些辅助处理,依次调用各处理函数,在 netdev_port_receive()【这里会进行数据包的拷贝,避免损坏】进入 ovs_vport_receive()回到 vport.c,从 ovs_dp_process_receive_packet()回到 datapath.c,进行统一处理

收包处理

  1. ovs_vport_receive_packets()调用ovs_flow_extract基于skb生成key值,并检查是否有错,然后调用ovs_dp_process_packet。交付给datapath处理
  2. ovs_flow_tbl_lookup_stats。基于前面生成的key值进行流表查找,返回匹配的流表项,结构为sw_flow
  3. 若不存在匹配,则调用ovs_dp_upcall上传至userspace进行匹配。 (包括包和key都要上传)
  4. 若存在匹配,则直接调用ovs_execute_actions执行对应的action,比如添加vlan头,转发到某个port等。

upcall 消息处理

  1. ovs_dp_upcall()首先调用err=queue_userspace_packet()将信息排队发到用户空间去
  2. dp_ifindex=get_dpifindex(dp)获取网卡设备索引号
  3. 调整 VLAN的 MAC 地址头指针
  4. 网络链路属性,如果不需要填充则调用此函数
  5. len=upcall_msg_size(),获得 upcall 发送消息的大小
  6. user_skb=genlmsg_new_unicast,创建一个新的 netlink 消息
  7. upcall=genlmsg_put()增加一个新的 netlink 消息到 skb
  8. err=genlmsg_unicast(),发送消息到用户空间去处理

参考

 

标签:OVS,dl,vsctl,ovs,--,00,vSwitch,Open,port
来源: https://blog.csdn.net/Rong_Toa/article/details/117162935