最近OVS-DPDK做分片重组的时候,遇到一些问题,所以现在大致看了一下分片思路和代码,现在记录一下。DPDK版本为16.11.1

分片试验


因为涉及到封装,所以我的分片不是基于标准的MTU 1500,而是基于1422,我采用ICMP报文,长度5000。以下记录了一下打印信息。从打印的信息可以看到,分片并尽量不使用copy,所以导致于新的分片都都几个段组成,中间记录了一些偏移量。

in_packet
buf_addr 0x7f49901b8180, data_off 128, buf_len 2184, nb_segs 4, pkt_len 5042, data_len 1514
buf_addr 0x7f49908ac680, data_off 162, buf_len 2184, nb_segs 3, pkt_len 1480, data_len 1480
buf_addr 0x7f49908abb40, data_off 162, buf_len 2184, nb_segs 2, pkt_len 1480, data_len 1480
buf_addr 0x7f49908ab000, data_off 162, buf_len 2184, nb_segs 1, pkt_len 568, data_len 568
out_packet
buf_addr 0x7f49908aa4c0, data_off 114, buf_len 2184, nb_segs 2, pkt_len 1456, data_len 34
buf_addr 0x7f49901b8180, data_off 162, buf_len 2184, nb_segs 1, pkt_len 1500, data_len 1422
out_packet
buf_addr 0x7f49908a8e40, data_off 114, buf_len 2184, nb_segs 3, pkt_len 1456, data_len 34
buf_addr 0x7f49901b8180, data_off 1584, buf_len 2184, nb_segs 1, pkt_len 1500, data_len 58
buf_addr 0x7f49908ac680, data_off 162, buf_len 2184, nb_segs 1, pkt_len 1480, data_len 1364
out_packet
buf_addr 0x7f49908a6c80, data_off 114, buf_len 2184, nb_segs 3, pkt_len 1456, data_len 34
buf_addr 0x7f49908ac680, data_off 1526, buf_len 2184, nb_segs 1, pkt_len 1480, data_len 116
buf_addr 0x7f49908abb40, data_off 162, buf_len 2184, nb_segs 1, pkt_len 1480, data_len 1306
out_packet
buf_addr 0x7f49908a4ac0, data_off 114, buf_len 2184, nb_segs 3, pkt_len 776, data_len 34
buf_addr 0x7f49908abb40, data_off 1468, buf_len 2184, nb_segs 1, pkt_len 1480, data_len 174
buf_addr 0x7f49908ab000, data_off 162, buf_len 2184, nb_segs 1, pkt_len 568, data_len 568

入报文,长度位5042(icmp 5000+8+20+14)
第一个报文是偏移162开始L4数据,长度1480
接下来的2个报文也都是偏移162开始,长度1480
最后一个报文偏移162开始,长度568

mtu 1442
出报文4个,总长度5144
第一个报文新建一个L2和L3的头,接着使用入报文1的L4开始的数据,长度位1422,总长度34+1422=1456
第二个报文新建一个L2和L3的头,接着使用入报文1的偏移1584(1422+162),长度58(报文长度1422+58=1480),接着使用入报文2的偏移162,长度1364,所以总长度34+58+1364=1456
第三个报文新建一个L2和L3的头,接着使用入报文2的偏移1526(1364+162),长度116(报文长度1364+116=1480),接着使用入报文3的偏移162,长度1306,所以总长度34+116+1306=1456
第四个报文新建一个L2和L3的头,接着使用入报文3的偏移1468(1306+162),长度174(报文长度1306+174=1480),接着使用入报文4的偏移162,长度568,所以总长度34+174+568=776

代码查看出现的问题


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)
{
    ...

    //此处问题就是分片大小计算的时候默认IP协议头是20,不包含option
    //以下还有几处存在这个问题,需要注意
    frag_size = (uint16_t)(mtu_size - sizeof(struct ipv4_hdr));

    //此处要求分片大小必须是8的倍数,但是非debug版本这块是忽略的
    //函数外保证这一点的话,会比较麻烦,因为mtu_size和ip头长度一起决定的
    //分片大小反正是这里计算的,所以计算的时候保证是8的倍数比较好
    RTE_ASSERT((frag_size & IPV4_HDR_FO_MASK) == 0);

    //所以以上两个问题推荐合并两行代码为以下一行代码
    frag_size = (uint16_t)((mtu_size - ((in_hdr->version_ihl & 0xf) << 2)) & 0xfff8);

    ...
}
最后修改:2021 年 08 月 18 日 02 : 29 PM