DPDK ipv4 ip分片与重组

本文简介一下DPDK在处理ipv4类型的数据包的ip分片和重组。主要描述的是分片和重组过程中mbuf的管理及调用API时需要注意的事项。至于分片和重组功能实现的细节,代码并不难懂,这里就不赘述了。

IPv4 Fragment

API:

int32_t 

rte_ipv4_fragment_packet (struct rte_mbuf *pkt_in, struct rte_mbuf **pkts_out, uint16_t nb_pkts_out, uint16_t mtu_size, struct rte_mempool *pool_direct, struct rte_mempool *pool_indirect)

 

1、调用此API之前需要搞清楚mbuf中Direct mbuf和Indirect mbuf的概念,官方文档的描述非常的清晰,不清楚的话去看一下:

http://dpdk.org/doc/guides/prog_guide/mbuf_lib.html

2、参数pkt_in,此时的mbuf数据的偏移位置需在ip头部。可通过rte_pktmbuf_adj()进行调整。分片完成之后的输出mbuf的数据指针位置也会在ip头部的位置,如果发送此分片的话使用rte_pktmbuf_prepend调整。

3、参数pool_indirect是在分片过程中需要的indirect mbuf的内存池,在初始化时申请。

4、mtu_size需要注意一下,分片的数据长度需要是8的整数倍,在计算分片数据的offset时会用到此参数。mtu_size-20(DPDK定义的ipv4头部结构体长度)需要是8的整数倍。

分片mbuf管理

mbuf的结构如下图所示。

DPDK ipv4 ip分片与重组_第1张图片

下面我们来介绍一下DPDK如何通过mbuf的管理实现分片的零拷贝。

DPDK ipv4 ip分片与重组_第2张图片

如上图所示,假设根据mtu原始的packet需要被分片为两个分片。在分片成功之后我们可以看到原来的一个mbuf变成了两个,这两个分片的mbuf有以下特点:

1、  分片的mbuf中的数据部分只存有分片后的ipv4的头部信息;

2、  每个分片mbuf都有一个Indirectmbuf,这个indirect mbuf包含分片的数据的部分,它是通过指针指向了分片前的数据偏移。

3、  此mbuf的数据指针此时在l3层的位置。

至此我们可以看出,将一个packet分为两个分片需要5个mbuf的同时使用,在使用完毕后,一定要通过rte_pktmbuf_free()来对mbuf进行回收,此接口会根据mbuf的引用计数及类型释放相关联的mbuf,否则会出现mbuf资源得不到回收的情况。

IPv4 Reassemble

API:

struct rte_mbuf * 

rte_ipv4_frag_reassemble_packet (struct rte_ip_frag_tbl *tbl, struct rte_ip_frag_death_row *dr, struct rte_mbuf*mb, uint64_t tms, struct ipv4_hdr *ip_hdr)

 

1、参数rte_ip_frag_tbl是用来暂存分片的表,通过rte_ip_frag_table_create()创建。这个接口的声明如下

struct rte_ip_frag_tbl * 

rte_ip_frag_table_create (uint32_t bucket_num, uint32_t bucket_entries, uint32_t max_entries, uint64_t max_cycles, int socket_id)

参数max_crycles指的是分片超时时间。是以cpu cycle来计算的,举个栗子。

frag_cycle = (rte_get_tsc_hz()) + MS_PER_S –1) / MS_PER_S * 10;

这句代码是10ms的cycle的一个例子。rte_get_tsc_hz() 函数返回的是1s的CPU频率是多少HZ, 然后按毫秒到秒的进制转换对该值进行一个向上取整得到每一毫秒的CPU频率。之后乘以10就是10毫秒的CPU cycle了。

2、在调用rte_ipv4_frag_reassemble_packet()接口的时候,参数tms通过rte_rdtsc()来进行赋值即可。

3、调用此接口时需要填充mbuf结构体重的l2_len和l3_len。

4、分片重组成功后会返回第一个分片所在的mbuf地址,此时此mbuf中的数据部分已被填充为一个完整的以太网包,ip头部中的字段也看不到分片的影子,数据通过next指针连接。

重组mbuf管理

以两个分片重组一个数据包为例。

DPDK ipv4 ip分片与重组_第3张图片

分片重组的过程中不会使用新的mbuf,只是在原来的mbuf的基础上做一些修改。当然了,原来的分片信息并没有被清掉,如果在重组完成后利用原来的分片ip头部信息,通过Data指针偏移即可访问。重组后的mbuf有一下特点:

1、  mbuf通过next指针将分片链接为一个完整的以太网包,其中第一个分片所在的mbuf中存储了整个以太网包的长度,完整的新的IP头等信息。

2、  包含有第一个分片的mbuf的数据buf_addr指针在l2的位置,其他分片的buf_addr指针在data_off+l2_len+l3_len的位置,即buf_addr指向ipv4负载。

3、  当发生分片丢失造成超时时,超时分片会被加入到death_raw链表上(初始化frag_table时指定),在处理业务时,需要显示调用rte_ip_frag_free_death_row()来回收超时的分片。

重组后的L3 checksum计算

分片数据如需重新计算l3 checksum对数据进行校验,首先必须将数据包重组。DPDK(at least 16.11)提供了一个接口对分布在多个mbuf中的数据进行校验和计算。

static int 

rte_raw_cksum_mbuf (const struct rte_mbuf *m, uint32_t off, uint32_t len, uint16_t *cksum)

1、  此接口计算的是数据部分的校验和,只包含l4头部和数据。

2、  对这个接口的off和len参数说明一下。

off: 数据开始的偏移位置,重组后第一个mbuf的数据指针在l2位置,所以需要偏移l2_len+l3_len的位置;

len: 不包含l2和l3以外的数据长度。

3、  根据L4 checksum的计算方法,我们还需要添加一个伪头部计算结构,2个字节加权后翻转即得到L4的checksum值。伪头部的计算使用rte_ipv4_phdr_cksum()接口。

你可能感兴趣的:(DPDK)