Open vSwitch中的datapath flow匹配过程
- 数据结构看不懂
- 匹配算法经过了多次演进,已经有点复杂了,看代码完全看不懂,我能怎么办,我也很绝望啊!
- 在创建一个vxlan型的vport时,会调用到vxlan_create来创建这个vport,这个函数做了两件事情
- 调用vxlan_tnl_create,alloc要创建的vport,并创建好vxlan设备
- 调用ovs_netdev_link,把上一步创建的vxlan设备与vport绑定起来,并且还注册了一个收包回调函数是为netdev_frame_hook,如下:
- netdev_frame_hook收到包后,把包转交给netdev_vport_receive,但由于不知道这个宏USE_UPSTREAM_TUNNEL功能是什么,所以到底转交的时候带不带第二个参数就搞不清楚了,如下
这里要注意的是,netdev_frame_hook及netdev_port_receive是标准的收包流程,所谓标准指的是,只要是发向OVS中port的包,无论port是什么类型,是VXLAN vport,还是netdev vport,还是gre vport,走的都是这个流程,这些vport类型的收包回调统一都是netdev_frame_hook - 无论什么vport类型,包都会走netdev_frame_hook->netdev_port_receive这个流程,然而在netdev_port_receive中就要分流了,如下:
在这个函数中,根据skb下挂的dev,找出该包所收包时所属于的vport,然后调用ovs_vport_receive - 接下来到了ovs_vport_receive函数中,这个函数主要就做了一件事情:把包中的标识信息(一二三四层外加conntrack信息)扒到一个sw_flow_key结构中,这个结构并不复杂,字段也比较容易理解,这个sw_flow_key结构就是后续datapath转发表匹配时很关键的一个东西。把这件事做完后,就把skb本身与扒出来的这个sw_flow_key一起送给ovs_dp_process_packet函数中进行进一步处理
- ovs_dp_process_packet如下
在这个函数中,将调用ovs_flow_tbl_lookup_stats()进行datapath转发表项的匹配工作
第一个参数是查询的转发表,这个表挂在datapath下,类型为flow_table,看上面的数据结构图
第二个参数是之前扒出来的sw_flow_key类型结构实例
第三个参数是调用Linux kernel函数对skb进行的一个哈希数值
第四个参数是一个出参,如果是megaflow匹配的话,这个出参将携带掩码匹配命中的字段数出来 - 至此,先停一下车,上面说的是包是怎么收进来的,接下来就要看包是怎么匹配的了,先停一下车
- 第一个层次,假设没有megaflow,即按位选择性匹配,datapath转发表项必须全12个字段精确匹配,你会怎么做?这种情况下,匹配就很简单,我们把包中的信息扒到sw_flow_key结构中,然后在OVS中设计一个哈希表,映射的就是[sw_flow_key <==> 如何转发],直接用这个哈希表按key查询,O(1)就能完成匹配。
做个不恰当的比喻,内核datapath中实现了一个类似于std::map的数据结构,当然这是一个哈希表,其中键是sw_flow_key类型的,值就是“要执行的动作”(也就是sw_flow类型)
当packet收上来时,直接把packet解压出来的key当成键,去查询它对应的“要执行的动作”。。查询成功,就走快转直接从内核转走。。查询失败,就是内核datapath转发表项匹配失败,给用户态上送upcall消息。用户态根据OpenFlow流表,走慢转,然后再把慢转的行为总结成datapath转发表里的“要执行的动作”,下发给内核,这样,下一次再来,就直接走快转了。
但是问题出现了,精确匹配的最大缺点就是datapath转发表项数量会爆炸膨胀,你想一下用户态OpenFlow流表中的安全组的实现,conjunctive,你再想一想这些安全组映射成datapath转发表项,表项数量得炸成什么样。
所以为了解决这个问题,就出现了megaflow式匹配,这个洋文名字的意思就是:选择性的匹配某些字段 - megaflow匹配就是第二个层次
- 入的包解压出来的sw_flow_key实例是所有字段都有的
- 匹配时只需要匹配部分的sw_flow_key中的字段,所以OVS设计了一个数据结构叫sw_flow_mask,sw_flow_mask中有两个很重要的字段:sw_flow_key_range与sw_flow_key,其中range就指定了匹配哪些字段。。
比如,比如,举个不严谨的例子,datapath中要支持两种匹配:
第一种:按MAC层src与dst及IP层src与dst的匹配
第二种:IP层src与dst的匹配
那么就需要做两个sw_flow_mask实例,假设macsrc/macdst/ipsrc/ipdst的编号分别是3、4、5、6,那么这两个sw_flow_mask的实例的示意大致如下:
sw_flow_mask first = {
range = [3,4]
key = {
...
macsrc=11:22:33:44:55:66
macdst=66:55:44:33:22:11
...
}
}
sw_flow_mask second = {
range = [3,6]
key = {
...
macsrc=22:22:22:33:33:33
macdst=33:33:33:22:22:22
ipsrc=1.2.3.4
ipdst=4.3.2.1
...
}
}
然后这两个实例放在哪里呢?在(datapath.table)->mask_array中,在旧版本的OVS实现中,这些sw_flow_mask的实例被组织成链表,在2.7版本中,直接组织成顺序表了
那么packet收上来是如何进行匹配的呢?
首先,要对(datapath.table)->mask_array中的所有sw_flow_mask进行遍历
然后,对于每个sw_flow_mask实例,这里称为mask,去比对mask.range范围内,mask.key中的值,
如果这些值与packet解压出来的key一致,那么就表示megaflow匹配成功
这个时候接下来怎么搞呢?和第一步一样,依然是要去查哈希表,查出一个sw_flow出来,但是哈希表是全字段匹配的呀。
比如包原先解压出来的sw_flow_key是为key,这个时候用key作键去查哈希表,结果并不是我们希望得到的megaflow匹配结果,而是全匹配结果(很有可能会miss)
所以不能用key去当键去查哈希表,而应该用匹配的sw_flow_mask实例里的"range + key"这两个信息结合起来,当成键,去查哈希表。
在这一版的匹配流程中,相较于上一版,解决了datapath转发表项数量爆炸的问题。
并且在实际实现中,对于sw_flow结构,还增加了一个用来表示mask的字段,是为sw_flow->mask,类型是为sw_flow_mask
- 上一版的匹配流程虽然改善了datapath转发表项的爆炸问题,但是又引入了一个新的问题(真他妈是聋子治成哑巴了):性能下降了!
第一版虽然很浪费内存空间,但是查找快啊!只查一次哈希表就世界太平了!顶多桶位上链表长度长一点撑死了!
第二版虽然节省了空间,但又浪费时间了啊!你看,先要遍历所有的mask_array中的sw_flow_mask实例,来看哪个实例与包的key能对上!
所以OVS这拨人又处心积虑的搞出了第三版匹配流程。
核心思想还是站在前人的工作上糊一层屎:既然遍历mask_array里的实例太浪费时间,那么就不要以“遍历”的形式去做这件事,来,老子的意大利散列函数呢??想办法干他娘的一炮!
在上一版的策略中,流程大概是:
第一层:遍历mask
第二层:根据masked_key查询flow
所以这一版的策略就改进了这一点,现在流程是这样的:
第一层:根据packet的key,查询masked_key
第二层:根据masked_key,查询flow
注意这两个层次的查询都是哈希表(字典)查询,所以总共实现了两个哈希表(字典):
第一个字典:键为packet的标识信息,值为mask的标识信息
第二个字典:键为masked_key,值为flow
大概逻辑就是这样,下面将讲第三版匹配流程的具体实现
- ufid_ti的用途?
- sw_flow结构中,每个table_instance都对应着两个链表字段,为什么?
- table_instance结构中的node_ver是什么用途?
body,td { font-family: Consolas; font-size: 10pt }
Open vSwitch中的datapath flow匹配过程的更多相关文章
- 绝对路径${pageContext.request.contextPath}用法及其与web.xml中Servlet的url-pattern匹配过程
以系统的一个“添加商品”的功能为例加以说明,系统页面为add.jsp,如图一所示: 图一 添加商品界面 系统的代码目录结构及add.jsp代码如图二所示: 图二 系统的代码目录结构及add.js ...
- (转)绝对路径${pageContext.request.contextPath}用法及其与web.xml中Servlet的url-pattern匹配过程
以系统的一个“添加商品”的功能为例加以说明,系统页面为add.jsp,如图一所示: 图一 添加商品界面 系统的代码目录结构及add.jsp代码如图二所示: 图二 系统的代码目录结构及add.js ...
- web.xml中的url-pattern写法规则及匹配过程
servlet和filter在javaEE开发中很常用,因此有必要知道web.xml文件映射的规则 1. 写法 ①完全匹配:以“/”开头,以字母(非“*”)结束 如:<url-patte ...
- 在Python中使用正则表达式同时匹配邮箱和电话并进行简单的分类
在Python使用正则表达式需要使用re(regular exprssion)模块,使用正则表达式的难点就在于如何写好p=re.compile(r' 正则表达式')的内容. 下面是在Python中使用 ...
- 【java规则引擎】模拟rete算法的网络节点以及匹配过程
转载请注明:http://www.cnblogs.com/shangxiaofei/p/6340655.html 本文只用于理解rete算法,通过一个规则的编译成的网络结构,以及匹配过程去理解rete ...
- Java中对象方法的调用过程&动态绑定(Dynamic Binding)
Java面向对象的最重要的一个特点就是多态, 而多态当中涉及到了一个重要的机制是动态绑定(Dynamic binding). 之前只有一个大概的概念, 没有深入去了解动态绑定的机理, 直到很多公司都问 ...
- Python妙用re.sub分析正则表达式匹配过程
声明:本文所使用方法为老猿自行研究并编码,相关代码版权为老猿所有,禁止转载文章,代码禁止用于商业用途! 在<第11.23节 Python 中re模块的搜索替换功能:sub及subn函数>介 ...
- Python正则表达式书写容易碰到的陷阱:\W*和\W*?匹配过程遇到的问题
老猿在分析<Python正则表达式\W+和\W*匹配过程的深入分析>中的问题时,想到一个问题,如果"re.split('(\W*)','Hello,world')"的处 ...
- Python正则表达式\W+和\W*匹配过程的深入分析
在学习re.split函数的处理过程中,发现执行如下语句及返回与老猿预想的不一致: >>> re.split('\W*','Hello,world') ['', 'H', 'e', ...
随机推荐
- (一)一起学 Java Collections Framework 源码之 概述
. . . . . 目录 (一)一起学 Java Collections Framework 源码之 概述 JDK 中很多类 LZ 已经使用了无数次,但认认真真从源码级研究过其原理的还只占少数,虽然从 ...
- 关于sql、mysql语句的模糊查询分类与详解,包括基本用法和mapper.xml文件里插入写法
欢迎猿类加qq:2318645572,共同学习进步 实际例子: ssm框架:service业务层->dao层->mappers.xml->junit/test测试 1:service ...
- Linux-进程描述(2)之进程标识符与进程位置
在上一篇文章中详细介绍了task_struct结构体内的常见成员,然后我们就来看一下具体内容.每个进程都把它的信息放在 task_struct 这个数据结构中,task_struct 包含了这些内容: ...
- 复选框选中删除行(DOM练习)
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- Xamarin.Forms+Prism(3)—— 简单提示UI的使用
这次给大家介绍两个比较好用的提示插件,如成功.等待.错误提示. 准备: 1.新建一个Prism Xamarin.Forms项目: 2.右击解决方案,添加NuGet包: 1)Acr.UserDialog ...
- JS属性描述符
var myObject = { a:2 }; Object.getOwnpropertyDescriptor(myObject,"a"); { value:2, writable ...
- Linux 基础(2)
Linux 基础(二) 用户 组 及权限的相关操作 一.useradd命令选项:–u:指定用户的UID useradd –u 100 mu #指定mu的UID为100–g:指定用户所属的群组 user ...
- .NET遇上Docker - Docker集成Cron定时运行.NETCore(ConsoleApp)程序.md
配置项目的Docker支持 对于VS中Docker的配置,依旧重复一些废话. 给项目添加Docker支持,VS2015可以直接使用Docker for VS插件,VS2017在安装时选择容器支持.VS ...
- PHP array_filter() 函数
定义和用法 array_filter() 函数用回调函数过滤数组中的元素,如果自定义过滤函数返回 true,则被操作的数组的当前值就会被包含在返回的结果数组中, 并将结果组成一个新的数组.如果原数组是 ...
- cmd 命令行模式操作数据库 添加查询 修改 删除 ( 表 字段 数据)
一 查看数据库.表.数据字段.数据 1 首先配置环境变量 进入mysql 或者通过一键集成工具 打开mysql命令行 或者mysql 可视化工具 打开命令行 进入这样的界面 不同的机器操作不同 ...