dpdk提供了一个访问控制库,提供了基于一系列分类规则对接收到的报文进行分类的能力。
ACL库用来在一系列规则上执行N元组查找,可以实现多个分类和对每个分类查找最佳匹配(最高优先级),ACL库的api提供如下基本操作:
- 创建一个新的访问控制(AC)环境实例(context)
- 添加规则到这个环境实例
- 为这个实例里所有的规则,创建必需的运行时结构体来指针报文分类
- 执行接收报文分类
- 删除AC环境实例和对应的运行时结构体,并释放内存
概述
1. 规则定义
当前的实现允许用户对将要执行的报文分类需要的每一个context指定它独有规则(字段集合)。但这在规则字段上有一些限制条件:
规则定义的第一个字段必须是一个字节的长度
之后的字段必须以4个连续的字节分组
这主要是为性能考虑,查找函数处理第一个输入字节做为这个流的设置的一部分,然后这查找函数的内部循环被展开来同时处理4字节的输入。
要定义规则的每一个字段,需要使用如下的结构体:
struct rte_acl_field_def {
uint8_t type; /*< type - ACL_FIELD_TYPE. */
uint8_t size; /*< size of field 1,2,4, or 8. */
uint8_t field_index; /*< index of field inside the rule. */
uint8_t input_index; /*< 0-N input index. */
uint32_t offset; /*< offset to start of field. */
};
type
字段的类型,有3种选项:
_MASK 表示有值和掩码的IP地址字段,定义相关的bit位
_RANGE 表示端口字段的低位和高位值
_BITMASK 表示协议标识字段的值和掩码位
size 这个参数定义了字段的字节数大小。允许的值范围有(1,2,4,8)bytes,注意,由于输入字节的分组,1或2字节的字段必须定义为连续的来组成4字节连续。通用,最好的做法是定义8或更多字节数的字段,这样构建进程会消除那些乱的字段。
field_index
一个0开始的值,用来指定字段在规则内部的位置,0~n-1表示n个字段。
input_index
上面提到过,所有输入字段除了第一个其他必须以4个连续字节分组,这个input_index就是指定字段在那个组。
offset
这个定义了字段的偏移量,为查找指定了从缓冲区的起始位置的偏移。
举个栗子,定义一个IPv4的五元组的分类:
struct ipv4_5tuple {
uint8_t proto;
uint32_t ip_src;
uint32_t ip_dst;
uint16_t port_src;
uint16_t port_dst;
};
需要使用下面的字段定义数组:
struct rte_acl_field_def ipv4_defs[5] = {
/* first input field - always one byte long. */
{
.type = RTE_ACL_FIELD_TYPE_BITMASK,
.size = sizeof (uint8_t),
.field_index = 0,
.input_index = 0,
.offset = offsetof (struct ipv4_5tuple, proto),
},
/* next input field (IPv4 source address) - 4 consecutive bytes. */
{
.type = RTE_ACL_FIELD_TYPE_MASK,
.size = sizeof (uint32_t),
.field_index = 1,
.input_index = 1,
.offset = offsetof (struct ipv4_5tuple, ip_src),
},
/* next input field (IPv4 destination address) - 4 consecutive bytes. */
{
.type = RTE_ACL_FIELD_TYPE_MASK,
.size = sizeof (uint32_t),
.field_index = 2,
.input_index = 2,
.offset = offsetof (struct ipv4_5tuple, ip_dst),
},
/*
* Next 2 fields (src & dst ports) form 4 consecutive bytes.
* They share the s