OVS定义
OVS是OpenvSwitch简称,官方定义OVS是一个产品级质量的多层虚拟交换机。通过支持可编程扩展来实现大规模的网络自动化。为了方便管理和配置虚拟机网络,所以直接将ovs部署到硬件设备上作为控制层。OVS包含三个重要的组件:ovsdb-server、ovs-vswitchd、以及OVS内核模块.
- ovsdb-server:OVS持久化存储的数据库,用于记录的网桥、端口、QOS等网络配置信息。
- ovs-vswitchd:交换机的主要模块,运行在用户态,负责保存和管理控制器下发的流表,通知OVS内核如何处理数据包。
- ovs内核模块openvswitch.ko:运行在内核态,属于快速转发平面,主要负责流表匹配、报文修改、隧道封装、并且维护底层转发表。
OVS各模块交互
- ovs-vswitchd与控制器通信使用openflow协议。
- ovs-vswitchd与ovsdb-server通信使用OVSDB协议。
- ovs-vswitchd和内核模块通过netlink通信。
ovs-vswitchd在启动时会读取ovsdb-server中配置信息,然后配置内核中的datapaths,当ovsdb中的配置信息改变时ovs-vswitchd也会自动更新其配置以保持与数据库同步。ovs-vswitchd需要加载datapath内核模块才能正常运行。
OpenFlow协议
OpenFlow是一种用于软件定义网络(SDN)的开放通信协议,旨在通过将网络的控制平面与数据平面分离,实现网络的灵活性和可编程性。在SDN中,控制器可以通过OpenFlow协议向网络设备下发流表规则,指示网络设备如何处理数据包,从而实现更灵活和动态的网络配置。
openflow有255个分类器,对应255个table,每个table里的流表按照优先级排序。
ofproto结构体
ofproto :ovs中负责实现 OpenFlow 协议。ofproto用来表示一个bridge网桥。
oftable:bridge上最多可以有255个oftable,即openflow流表table个数。
classifier:pipeline里的每个table对应一个Classifier分类器。
subtables:classifier把整张表里的所有rule根据tss算法分类分成了不同的subtable,查找流表时遍历subtable,最坏情况下需要查找所有的subtable。
cls_subtable:具有相同mask掩码的rule集合。
priority:选出cls_subtable里优先级最高的rule作为priority,匹配时由高到低排序,一旦在当前cls_subtable的rule里匹配上,且该rule的优先级大于后续cls_subtable的priority可以直接跳过。
rules:所有rule都是以hash桶的形式存储,根据hash值分到不同的bucket,bucket里是rule链表。
flow_segments[3]:分段查找,rule的匹配项按四个子类来分metadata,L2, L3,L4第一阶段先匹配metadata;然后再匹配metadata,L2;继续metadata,L2,L3;最后才是metadata,L2,L3,L4。对于能匹配的rule其实并不能增加效率,但是对于不匹配的情况却是可以增加很大效率。
priority=200, ip, nw_dst=11.0.0.0/8 dst_port=80 action=output:1
priority=100, ip, nw_dst=10.0.0.0/8 action=output:2
数据包:10.5.6.6: 45666 -> 10.5.6.7:22
#未进行分段查找下发的megaflow
megaflow:ip,nw_dst=10.0.0.0/8, dst_port=22 action=output:2
#分段查找后下发的megaflow
megaflow:ip,nw_dst=10.0.0.0/8 action=output:2
max_priority:保存所有流表的优先级的最大值,这样在查找流表时,按照优先级从高到低遍历subtables,如果找到了匹配流表将其保存在保存到临时变量temp中,遍历下一个subtable时,如果subnet.max_priority小于temp中的priority,表示该subnet中不会有优先级更高的匹配,可以跳过该subent,如果遇到优先级更高的匹配流表,更新temp值继续遍历。
tire:所有的subtable共用相同的trie。将每一个ip分割的4个“8位二进制数”当作树的一个节点,当需要匹配ip地址时,在查找hash表前,先根据LPM查找前缀树,来决定megaflow流表需要的最长前缀,如果遇到了叶子节点,说明查找成功,可以结束查找,下发到megaflow流表,没有匹配到节点而导致查找结束,也要将查找失败的bit安装到megaflow。
priority=200, ip, nw_dst=11.5.6.7/32 dst_port=80 action=output:1
priority=100, ip, nw_dst=10.0.0.0/8 action=output:2
数据流 10.5.6.6: 45666 -> 10.5.6.7:22
#未进行LPM前缀树查找下发的megaflow
mefaglow:ip,nw_dst=10.5.6.7/32 action=output:2
#LPM前缀树查找后下发的megaflow
mefaglow:ip,nw_dst=10.0.0.0/8 action=output:2
n_rules:classifier里rule个数。
max_flows:支持最大openflow流表个数,默认为UINT_MAX。
n_flows:当前配置的流表个数。
miss_config:对openflow中未匹配到流表的操作(1)将报文通过packet-in消息发给controller (2)继续在下一个table进行匹配(3)直接丢包。
expirable:bridge上所有oftable中需要超时处理的openflow流表。
openflow流表添加过程
- 通过ovs-ofctl add-flow xxx添加一条流表时ovs-vswitchd处理handle_openflow请求。
- 获取flow的tableid,即找到对应的classifier。
- 分配rule结构体空间,将flow的match和action写入到rule结构体。
- 根据flow的mask找到对应的subtable,若未找到创建一个新的subtable。
- 将rule添加到subtable。
openflow流表查找过程
- 当数据包在ovs一级、二级缓存查找不到对应规则时,上送到ovs-vswitchd。
- 需要将数据包的ip与subtable的mask进行与操作,得到ip网段在rule中匹配
- 根据priority遍历subtables,在subtable里根据hash值找到对应的bucket,需要注意的是hash值不是1个,而是4个分别对应metadata,L2, L3,L4,此优化是结合分段查找,当第一个hash值不匹配时直接退出,写入到megaflow不再进行后续查找提高效率。
- 若4个hash值都匹配上,则可在bucket里拿到链表的头指针,遍历链表找到rule规则。
- 将匹配的流表插入一二级缓存,如果是ovs环境需要写入到microflow和megaflow,如果是ovs-dpdk需要写入emc和dpcls。
ovs添加网桥
通过ovs-vsctl命令创建网桥,将参数发送给ovsdb-server,ovsdb-server将数据写入数据库。ovs-vswitchd从数据库中读取网桥信息发送给ovs内核。
ovs添加网口
通过ovs-vsctl命令创建网口,将参数发送给ovsdb-server,ovsdb-server将数据写入数据库。ovs-vswitchd从数据库中读取网口信息发送给ovs内核。创建一个虚拟网卡并在内核注册hook函数,当从vport口收到包直接交给内核处理。
ovs在dp添加flow
通过ovs-dpctl添加流表将参数发送到内核模块,构造sw_flow结构体,提取flow的参数放入megaflow二级缓存,也是一个hash桶,key是数据hash值,value是链表结构的flow(简单介绍下,后续会文章会展开讲 )。
ovs添加openflow
通过ovs-ofctl命令创建flow是读取flow信息转换成openflow协议通过handle_openflow将参数发送到ovs-vswitchd,ovs-vswitchd里有专门负责处理openflow的进程不会发送到内核。当数据包在一级、二级缓存查找不到对应的规则时会上送到ovs-vswitchd查找openflow流表。