首页 > 代码库 > DPDK报文分类与访问控制

DPDK报文分类与访问控制

dpdk提供了一个访问控制库,提供了基于一系列分类规则对接收到的报文进行分类的能力。
ACL库用来在一系列规则上执行N元组查找,可以实现多个分类和对每个分类查找最佳匹配(最高优先级),ACL库的api提供如下基本操作:

  • 创建一个新的访问控制(AC)环境实例(context)
  • 添加规则到这个环境实例
  • 为这个实例里所有的规则,创建必需的运行时结构体来指针报文分类
  • 执行接收报文分类
  • 删除AC环境实例和对应的运行时结构体,并释放内存


概述
1.规则定义
当前的实现允许用户对将要执行的报文分类需要的每一个context指定它独有规则(字段集合)。但这在规则字段上有一些限制条件:
    规则定义的第一个字段必须是一个字节的长度
    之后的字段必须以4个连续的字节分组
这主要是为性能考虑,查找函数处理第一个输入字节做为这个流的设置的一部分,然后这查找函数的内部循环被展开来同时处理4字节的输入。
要定义规则的每一个字段,需要使用如下的结构体:

1 struct rte_acl_field_def {
2     uint8_t type;        /*< type - ACL_FIELD_TYPE. */
3     uint8_t size;        /*< size of field 1,2,4, or 8. */
4     uint8_t field_index; /*< index of field inside the rule. */
5     uint8_t input_index; /*< 0-N input index. */
6     uint32_t offset;     /*< offset to start of field. */
7 };


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的五元组的分类:

1 struct ipv4_5tuple {
2     uint8_t  proto;
3     uint32_t ip_src;
4     uint32_t ip_dst;
5     uint16_t port_src;
6     uint16_t port_dst;
7 };

需要使用下面的字段定义数组:

 1 struct rte_acl_field_def ipv4_defs[5] = {
 2     /* first input field - always one byte long. */
 3     {
 4         .type = RTE_ACL_FIELD_TYPE_BITMASK,
 5         .size = sizeof (uint8_t),
 6         .field_index = 0,
 7         .input_index = 0,
 8         .offset = offsetof (struct ipv4_5tuple, proto),
 9     },
10     /* next input field (IPv4 source address) - 4 consecutive bytes. */
11     {
12         .type = RTE_ACL_FIELD_TYPE_MASK,
13         .size = sizeof (uint32_t),
14         .field_index = 1,
15         .input_index = 1,
16         .offset = offsetof (struct ipv4_5tuple, ip_src),
17     },
18     /* next input field (IPv4 destination address) - 4 consecutive bytes. */
19     {
20         .type = RTE_ACL_FIELD_TYPE_MASK,
21         .size = sizeof (uint32_t),
22         .field_index = 2,
23         .input_index = 2,
24         .offset = offsetof (struct ipv4_5tuple, ip_dst),
25     },
26     /*
27     * Next 2 fields (src & dst ports) form 4 consecutive bytes.
28     * They share the same input index.
29     */
30     {
31         .type = RTE_ACL_FIELD_TYPE_RANGE,
32         .size = sizeof (uint16_t),
33         .field_index = 3,
34         .input_index = 3,
35         .offset = offsetof (struct ipv4_5tuple, port_src),
36     },
37     {
38         .type = RTE_ACL_FIELD_TYPE_RANGE,
39         .size = sizeof (uint16_t),
40         .field_index = 4,
41         .input_index = 3,
42         .offset = offsetof (struct ipv4_5tuple, port_dst),
43     },
44 };

一个典型的IPv4五元组规则如下:

source addr/mask destination addr/mask source ports dest ports protocol/mask
192.168.1.0/24 192.168.2.31/32 0:65535 1234:1234 17/0xff


任何带有协议ID为17(UDP),源地址为192.168.1.[0-255],目的地址为192.168.2.31,源端口在[0-65535],目的端口为1234的ipv4报文将会匹配上面的规则。

定义IPv6 2元组: <protocol, IPv6 source address>的报文分类,
IPv6 头:

1 struct struct ipv6_hdr {
2     uint32_t vtc_flow; /* IP version, traffic class & flow label. */
3     uint16_t payload_len; /* IP packet length - includes sizeof(ip_header). */
4     uint8_t proto; /* Protocol, next header. */
5     uint8_t hop_limits; /* Hop limits. */
6     uint8_t src_addr[16]; /* IP address of source host. */
7     uint8_t dst_addr[16]; /* IP address of destination host(s). */
8 } __attribute__((__packed__));

需要使用下面的字段定义数组:

 1 struct struct rte_acl_field_def ipv6_2tuple_defs[5] = {
 2     {
 3         .type = RTE_ACL_FIELD_TYPE_BITMASK,
 4         .size = sizeof (uint8_t),
 5         .field_index = 0,
 6         .input_index = 0,
 7         .offset = offsetof (struct ipv6_hdr, proto),
 8     },
 9     {
10         .type = RTE_ACL_FIELD_TYPE_MASK,
11         .size = sizeof (uint32_t),
12         .field_index = 1,
13         .input_index = 1,
14         .offset = offsetof (struct ipv6_hdr, src_addr[0]),
15     },
16     {
17         .type = RTE_ACL_FIELD_TYPE_MASK,
18         .size = sizeof (uint32_t),
19         .field_index = 2,
20         .input_index = 2,
21         .offset = offsetof (struct ipv6_hdr, src_addr[4]),
22     },
23     {
24         .type = RTE_ACL_FIELD_TYPE_MASK,
25         .size = sizeof (uint32_t),
26         .field_index = 3,
27         .input_index = 3,
28         .offset = offsetof (struct ipv6_hdr, src_addr[8]),
29     },
30     {
31         .type = RTE_ACL_FIELD_TYPE_MASK,
32         .size = sizeof (uint32_t),
33         .field_index = 4,
34         .input_index = 4,
35         .offset = offsetof (struct ipv6_hdr, src_addr[12]),
36     },
37 };

一个典型的IPv4二元组规则如下:

source addr/mask protocol/mask
2001:db8:1234:0000:0000:0000:0000:0000/48 6/0xff

任何带有协议ID为6 (TCP),源地址在
[2001:db8:1234:0000:0000:0000:0000:0000 - 2001:db8:1234:ffff:ffff:ffff:ffff:ffff] 之间的报文会匹配上的规则。
























































































































































DPDK报文分类与访问控制