前言:DPDK的LPM模块实现了一种最长前缀匹配,其中的KEY是32位的,可以说是为查找路由量身定做的,为了实现快速查找,实现上使用了用空间换时间的思路。同时为了最大限度的减少查询次数,把32位的KEY值划分为24位和8位两张表中。这样的设计思路可以用于以后的前缀查找。本篇分析以16.07版本为例。
一. LPM的设计概览
对于路由的查找,有多种方法,前缀匹配,红黑树,各有优劣。这都在昭示着上帝创世界是均衡的。从统计上看,只有少数的路由网段深度大于24,因此使用了DIR-24-8表,大部分匹配在第一次查找时即可命中。
对于二级表tbl8,理论上有2的24次方个,但是我们不能存储这个多个表,否则总共的表项不就是232了嘛,相当于每个ip地址都有一个条目对应。所以,可以通过限定tbl8表中的组的数目,减少空间占用。每个组也可以再次限定条目的数目,最大自然就是256了。直接使用下面的图来表示:
在16.04版本后,比如16.07版本中,就出现了LPM操作的两套接口,如
rte_lpm_add_v20()
和rte_lpm_add_v1604()
,区别在于下一跳的值范围,v20版本是8位的,v1604是32位的。这里的下一跳并不是地址的下一跳,仅仅是表示一个索引,可以用来指示自己的表项。
二.LPM的代码实现
在代码分析上,我们以v20版本做分析,v1604的版本基本一样。
2.1 LPM路由的存储
路由的存储是从rte_lpm_add_v20()
开始的:
首先,获得网段,
ip_masked = ip & depth_to_mask(depth);
然后是把路由信息添进规则表--rule_add_v20()
,
规则表是按照掩码深度排的,共有32个组,分别对应不同的掩码深度。
既然是添加rule,首先要看是否已经有了这个rule。这里使用了lpm->rule_info
结构来存储每个组的第一个rule在rule table的index。所以,查找过程就是:先看对应深度的组是否有元素,如果没有,直接下一步插入,如果有,就找到对应组的第一个元素,然后遍历,找到就返回index,没找到就下一步插入。
主要来说一下这个插入位置,由于各个组的rule存储是连着的,没有空余位置,因此当要添