7. Mbuf Library
mbuf库提供了分配和释放缓冲区(mbufs)的能力,DPDK应用程序可以使用它来存储消息(报文)。消息(报文)实际存储在mempool中,使用Mempool Library.。
rte_mbuf 结构体可以携带网络数据包或通用控制缓冲区(由CTRL_MBUF_FLAG标识)。也可以扩展到其他类型。rte_mbuf头结构保持尽可能小,目前只使用两个cache lines,经常使用的字段需要放在两个cache lines的第一个。
7.1. Design of Packet Buffers
为了存储数据包数据(包括协议头),考虑了两种方法(元数据只是某一功能的数据缓存的总称):
- 在mbuf结构体的存储空间里的分出一个固定大小缓存作为元数据来存储数据包。
- 分配一个独立的缓存空间存储数据包,并将缓存空间地址保存到mbuf的元数据。
缓冲区管理器实现了一组相当标准的缓冲区访问函数来操作网络数据包。
7.2. Buffers Stored in Memory Pools
缓冲区管理器使用 Mempool Library来分配缓冲区。因此,它确保了在L3处理中,包头在channels和ranks中最优交叉存取。一个mbuf包含一个字段,该字段表明它来自的哪个内存池。当调用rte_ctrlmbuf_free(m)或rte_pktmbuf_free(m)时,mbuf返回到其分配池中。
7.3. Constructors
数据包操作和控制mbuf的操作函数由相应API提供。rte_pktmbuf_init()和rte_ctrlmbuf_init()函数初始化mbuf结构中一些字段,mbuf一旦被创建,这些字段就不能被用户修改(mbuf类型、分配池、缓冲区开始地址,等等)。这个函数作为一个回调函数参数,在内存池创建调用rte_mempool_create()时传入。
7.4. Allocating and Freeing mbufs
分配一个新的mbuf需要用户指定使用哪个内存池。对于任何新分配的mbuf,它包含一个长度为0段。数据偏移量被初始化为指定大小(RTE_PKTMBUF_HEADROOM),以便在缓冲区中保留一些空间。
释放mbuf意味着将其返回到分配内存池中。在内存池中存储时mbuf的内容不会被修改(作为free的mbuf)。构造函数初始化的字段不需要在mbuf再次分配时重新初始化。当释放的数据包含有多个mbuf时,所有这些mbuf都被释放并返回到自己所属的分配mempool。
7.5. Manipulating mbufs
这个库提供了一些函数来处理数据包mbuf中的数据。例如:获取数据长度
- 获取数据长度
- 获取数据起始位置指针
- 在数据前面添加数据
- 在数据后面添加数据
- 在缓冲区的开头删除数据(rte_pktmbuf_adj())
- 在缓冲区的末尾删除数据(rte_pktmbuf_trim()),详细参考 DPDK API Reference
- 计算out_ip的校验和
mb->l2_len = len(out_eth) mb->l3_len = len(out_ip) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM set out_ip checksum to 0 in the packet
当硬件通告DEV_TX_OFFLOAD_IPV4_CKSUM时标明支持这个特性。 - 计算out_ip和out_udp的校验和
mb->l2_len = len(out_eth) mb->l3_len = len(out_ip) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM | PKT_TX_UDP_CKSUM set out_ip checksum to 0 in the packet set out_udp checksum to pseudo header using rte_ipv4_phdr_cksum()
当硬件通告DEV_TX_OFFLOAD_IPV4_CKSUM和DEV_TX_OFFLOAD_UDP_CKSUM时标明支持这个特性。 - 计算in_ip的校验和
mb->l2_len = len(out_eth + out_ip + out_udp + vxlan + in_eth) mb->l3_len = len(in_ip) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM set in_ip checksum to 0 in the packet
这个和第一个案例类似,但是l2_len不同。当硬件通告DEV_TX_OFFLOAD_IPV4_CKSUM时标明支持这个特性。
注意,只有当出方向L4的校验和设置为0才能生效。 - 计算out_ip和out_tcp的校验和
mb->l2_len = len(out_eth + out_ip + out_udp + vxlan + in_eth) mb->l3_len = len(in_ip) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CSUM | PKT_TX_TCP_CKSUM set in_ip checksum to 0 in the packet set in_tcp checksum to pseudo header using rte_ipv4_phdr_cksum()
这个和第二个案例类似,但是l2_len不同。当硬件通告DEV_TX_OFFLOAD_IPV4_CKSUM 和 DEV_TX_OFFLOAD_TCP_CKSUM时标明支持这个特性。
注意,只有当出方向L4的校验和设置为0才能生效。 - tcp段
mb->l2_len = len(out_eth + out_ip + out_udp + vxlan + in_eth) mb->l3_len = len(in_ip) mb->l4_len = len(in_tcp) mb->ol_flags |= PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_TCP_SEG; set in_ip checksum to 0 in the packet set in_tcp checksum to pseudo header without including the IP payload length using rte_ipv4_phdr_cksum()
当硬件通告DEV_TX_OFFLOAD_TCP_TSO时标明支持这个特性。注意,只有当出方向L4的校验和设置为0才能生效。 - 计算out_ip,in_ip,in_tcp校验和
mb->outer_l2_len = len(out_eth) mb->outer_l3_len = len(out_ip) mb->l2_len = len(out_udp + vxlan + in_eth) mb->l3_len = len(in_ip) mb->ol_flags |= PKT_TX_OUTER_IPV4 | PKT_TX_OUTER_IP_CKSUM | \ PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM; set out_ip checksum to 0 in the packet set in_ip checksum to 0 in the packet set in_tcp checksum to pseudo header using rte_ipv4_phdr_cksum()
当硬件通告DEV_TX_OFFLOAD_IPV4_CKSUM,DEV_TX_OFFLOAD_UDP_CKSUM 和 DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM时标明支持这个特性。
struct rte_mempool *header_pool, *clone_pool;
header_pool = rte_pktmbuf_pool_create("header_pool", NB_HDR_MBUF, 32,
0, HDR_MBUF_DATA_SIZE, rte_socket_id());
clone_pool = rte_pktmbuf_pool_create("clone_pool", NB_CLONE_MBUF, 32,
0, 0, rte_socket_id());