最近在读一本书,high performance switches and routers。
第三章讲的是路由器内部功能实现需要解决的一个关键问题,根据内建路由转发规则转发packet。
其实质分为三部分,规则的组织形式,包的查找方式,规则的更新方式。由于规则的更新方式,和规则的查找方式都与规则的组织形式密切相关,因此也可以说classification的本质就是已有rules的组织存储形式。
书中将所有的分类方法按照规则组织形式分为四种,树形结构,图形结构,启发式(HEURISTIC)结构和TCAM-based的结构。
所有结构的评价可以分为三个主要维度(书中有6个维度):时间复杂度,空间复杂度,更新复杂度。而更新复杂度其本质也是结构时间开销的一部分,因此也可以算作时间复杂度。
这三个维度相互对立,其对立表现将在下文予以体现。
首先是一般规则结构
路由表规则一般包含以下6个字段:
Source IP(SIP),Destination IP(DIP),Source port(range), Destination port(range), Protocol, Action.
其中,SIP和DIP通常以prefix的形式存储,而不同算法对Port(range)各不相同。下图是一个4 fields的rule chart。
图暂缺。
Tree based classification
树形结构历史悠久,也是最简单的。
Hierarchical Tries
每条规则只存储一次,其余存储都是指向规则的pointer,因此此算法较为节省存储空间,其树形结构组织形式典型代表为二叉树,如下图所示:
图暂缺。
树形结构对prefix很直接但是对range无能为力。
为了提高树形查找的效率,利用空间换时间的思路设计了一种新树:
Set-Pruning Tries
从图中可以直观地看出这种结构是如何实现空间换时间的。
如何再对这种结构进行改进呢,利用时间换空间的思路,又出现了一种改进版:
Grid of Tries
可以看到,此树用pointer代替了重复的rule节点,节约了空间,但是浪费的时间在哪里呢?
浪费的时间在update time,由于部分节点被多个pointer指向,因此该类节点若发生变化,对应pointer都需要变换,这就是三维对立的第一个体现。
除了直观的树形结构,还有一类相对抽象的树形结构。
Extending Two-Dimensional Schemes
前文提到,树形结构非常适合对IP这类prefix的查找,但是对port等其它类型无能为力,因此在ISP提供商的主路由中,普遍采取了这样一种结构:
图暂缺。
- 执行对SIP和DIP的搜索,SIP和DIP的存储和检索方式可以采用任意合适的2D存储检索算法。
- 根据SIP和DIP的组合对rule进行分类,根据1的检索结果,再进入同类的rule集合搜索。
讲到这里基本上就可以引出Tree-based Classification的集大成者:
Field-Level Tree Classification (FLTC)
其本质即为以上思路的总结:对可用tree搜索的部分全部上tree,tree的子节点对应其余无法上tree的fields,在搜索到达子节点之后,采用其它搜索方式继续搜索,直到对应rule hit。如下图所示。
图暂缺。
可以看到,将rule的fields分为range和prefix两类之后,通过构建的树,我们直接将prefix组合/压缩之后存入TCAM,对于这一部分,采取TCAM搜索得到对应的rule set,之后再用k-way search进行range搜索。对range和prefix的搜索方式并不固定,但是这种分类搜索的思路非常经典自然,同时,由于分类的存在,对rule的删改也被限制在一定范围之中。论文对自己的评价非常高,可以支持10w到1百万的弹性增加并不损失查询性能。
GEOMETRIC ALGORITHMS
树形结构主要聚焦prefix并且将非prefix的fields转换为node类型实现上树,而geometric的思路则是将prefix也转化为range,因为geometric天然很适合对range进行分类。直接将不同rule的range分别转换为数轴上的范围,由此可以组成一个多维空间,而rule match问题就变成了多维空间点定位问题。
按照这个思路,我们得到了最基本形式的分类法:
Cross-producting Scheme
搜索是在每个维度依次进行的,因此最长搜索时间取决于最慢的那个维度以及维度数量。
此法最大问题在于存储空间,每个维度都存储了所有的rule,因此可能的组合数是 rule数量^维度数量。
图暂缺
由于上面一种方法的存储空间消耗过大,另一种方法被提出:
Bitmap-Intersection
此法基于一个观察结论:每个packet的最终匹配rule结果,是每个维度结果的交集,每个维度匹配的结果,是总rule集合的子集。
由于交集操作非常简单,因此我们只需要用最有效的方法搜索得到每个结果的子集,由此我们利用bitmap存储每个维度的rule分布,再进行搜索就可以大大简化匹配的复杂程度。
在每个维度搜索都会得到一个bit 序列,每个bit 序列与运算之后取最高/最低位就是最佳匹配的rule。
图暂缺
Parallel Packet Classification(P2C)
此法和上一种方法基本一致,只是在每个维度搜索得到的结果并非bit序列而是vector,然后将vector组合之后输入TCAM得到匹配的rule,这种方法本质上就是利用TCAM加快了后续的匹配。当然,vector与bitmap稍有不同,其组织形式为TCAM进行了优化,目的是在TCAM条数和TCAM输入位宽两者中取得平衡。
图暂缺
之后就是图的一种特殊形式,其本质还是tree,只是利用图来构建tree。
Area-Based Quadtree
凡是无法被分入子图的rule记为该级别图的node之中,取名为CFS(Crossing filter set).
由于每个rule只被存储了一次,因此此方法较为节省空间。
并且由于搜索时每次都是在四个分支和自己节点内部搜索,因此搜索时间与树深度相关,单个节点搜索时间近似为一个常数。
Hi-Cut
这个方法同样是树图结合的一个变种。本质上还是利用图来建树。
首先设定一个值,当所有节点内部的rule数量小于等于这个值的时候就停止。
建树的方法很简单,根据构造的图,按照平行于某个坐标轴的方向切割,切几次没有定数,目的是产生一些包含rule数量小于设定值的区域。
当一个坐标轴的切割已经无法生成更多满足上述条件的区域之后,开始在另一个坐标轴方向切割。如此循环往复知道所有坐标轴都切割完毕。
此法的问题在于树的深度还是比较高,影响搜索时间,并且有一些rule很难在一个方向被切割干净,因此会被重复存储,浪费空间。
由此变诞生了下面一种方法:
Hyper-cut
此法跟Hi-cut的区别在于每次从多个坐标轴开切,因此,切出来的区域更小,切割更精细,所以树的高度更小,重复存储的rule数量也更少。
因此,在搜索时间和存储空间上都超过了Hi-cut。
但是,提升并非没有代价,它的预计算时间都超过了Hi-cut,并且由于它的存储结构高度特化,对于规则的更新不友好。
HEURISTIC algorithm
这个词语不知道怎么翻译,就先不翻译了,其本质时通过预编码的方式,与bitmap和P2C类似,但是编码之后的处理方式有所不同。
Recursive Flow Classification(RFC)
这个方法的做法非常地直觉和简单。即将rule的字段先两两合并编码,结果再继续合并编码,最后得到一张总表,bit数量就大大缩小。
在这个过程中,所有的编码表都保存。
当一个packet到来的时候,根据编码表得到这个packet的最终编码,在总表中进行查找,就能得到最后的对应rule。
此法的问题也非常明显,第一个是删改时的重更新,第二是存储,因为字段实际上至少会被重复存储两次,所以rule多了之后空间消耗也比较大。
Tuple Space Search(TSS)
此法相对来说与FLTC类似,因为它将prefix和range分开。
首先根据prefix中的二元搜索组的长度把所有rule进行分类,同时,对于range进行编码,根据range的大小决定层级,同级再赋予一个id,将编号的编号和prefix一起做成hash表。
因此每个hash表都是对应一个特定长度的二元搜索组。
当有新包到达时,先将其range fields编码,然后根据设定的优先级到不同的hash表中进行搜索。得到最高优先级结果之后暂停搜索。
TCAM-based algorithm
Range Mapping in TCAMs
此法与TSS很像,因为TCAM很适合搜索prefix,所以只要解决将range映射到TCAM条目的问题之后(也称range mapping),就可以全部利用TCAM实现classification了。
TSS给出了一个映射的方法:根据range本身的大小将其分级再编码。
除此之外,此书还给出了另一种方法,这种方法和之前的bitmap以及P2C类似,直接对range进行编码,并不区分优先级。
首先将rule中所有的range包括点进行编码,这一步是采取了独热码,之后,对于不重叠的range采用二进制编码节省bit位宽,对于点,由于点也可以看成range为1且不重叠的range,因此也可以直接编码,由此实现了range mapping。
由于此法和RFC类似,都是针对某一个rule 表高度特化的方法,一旦有新的rule删改,需要重新编码,因此对更新也不友好。
总结
- Tree很适合prefix,不适合range。
- Geometric适合range,不适合prefix。
- 想结合tree和geometric的思路也有。比如area-based quadtree和 cut得到的tree。
而把range和prefix分开并且分别用tree和geometric map编码也可以。 - 采用TCAM作为特殊的硬件有它的优势,TCAM适合prefix,因此area-based和cut理论上都可以利用TCAM实现。
而更直接的做法是利用range mapping直接把range转换为类prefix的数据存入TCAM。 - 另外就是预编码,预编码对更新不友好,但是可以简化存储结构,实现减少存储空间并加快搜索速度的目的。
纯粹的预编码就是RFC方式,而部分预编码则是TSS。