实现dpdk分片重组

DPDK是一个用户空间的高性能数据包处理框架,可以用于以太网接口的快速报文处理。DPDK的分片重组功能能够将大于MTU的报文分片进行重组,以达到提高数据传输效率的目的。

DPDK分片重组的实现原理是在内存中维护一个待重组的缓存池,对接收到的分片进行缓存,等到所有的分片数据到达后进行重组,然后再将重组好的大数据报送往网络协议栈进行后续处理。

下面是DPDK的分片重组示例代码,目的是将数据报分片后,再进行重组:

#include <rte_ethdev.h>

#define NB_MBUF   8192
#define MAX_PACKET_SZ  2048
#define MBUF_CACHE_SIZE 256

struct mbuf_table {
    uint16_t len;
    struct rte_mbuf *m_table[MAX_PACKET_SZ];
};

struct pkt_seg {
    struct rte_mbuf *pkt;
    struct rte_mbuf *seg;
    uint32_t offset;
};

struct reassemble_data {
    uint32_t hash;
    uint32_t next_expected_seq;
    uint32_t nb_seg;
    struct pkt_seg seg[3];
};

struct mbuf_table mb_tbl[NB_MBUF];
struct reassemble_data reas_data[NB_MBUF];

/* 初始化由RTE mempool分配的缓存池 */
void init_mbuf_pool(){
    struct rte_mempool *mbuf_pool;
    mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF * MAX_PACKET_SZ,
        MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
}
/* 分片缓存 */
int cache_reassemble_packet(struct rte_mbuf *pkt, struct rte_mbuf *seg) {
    uint32_t hash;
    uint32_t next_expected_seq;
    uint32_t nb_seg;
    struct pkt_seg *pkt_seg = NULL;
    uint16_t i;
    struct reassemble_data *reas_data_entry = NULL;
    uint32_t offset = seg->pkt.data_len - sizeof(struct ipv4_hdr) -
        sizeof(struct udp_hdr);
    if (offset == 0){
        /* 不需要重组 */
        return -1;
    }
    hash = get_hash(pkt, seg);
    int i;
    for (i = 0; i < NB_MBUF; i++) {
        reas_data_entry  = &reas_data[i];
        if (reas_data_entry->hash == hash){
            break;
        }
    }
    if (i < NB_MBUF) {
        /* 数据包已缓存,进行分片重组过程 */
        struct pkt_seg *pkt_seg;
        next_expected_seq = reas_data_entry->next_expected_seq;
        nb_seg = reas_data_entry->nb_seg;
        for (i = 0; i < nb_seg; i++) {
            pkt_seg = &reas_data_entry->seg[i];
            if (pkt_seg->offset == (next_expected_seq - offset)){
                /* 当前分片匹配缓存中已存分片,进行重组 */
                reas_data_entry->next_expected_seq = next_expected_seq +
                    pkt_seg->seg->pkt.data_len -
                    sizeof(struct ipv4_hdr) -
                    sizeof(struct udp_hdr);
                pkt_seg->pkt->pkt.data_len = reas_data_entry->next_expected_seq;

                return reas_data_entry->next_expected_seq;
            }
        }
        if (reas_data_entry->nb_seg < 3) {
            /* 将当前分片加入缓存中 */
            pkt_seg = &reas_data_entry->seg[nb_seg];
            pkt_seg->offset = pkt->pkt.data_len - sizeof(struct ipv4_hdr) -
                sizeof(struct udp_hdr);
            pkt_seg->pkt = pkt;
            pkt_seg->seg = seg;
            reas_data_entry->nb_seg++;
        }
    } else {
        /* 缓存中不存在当前数据包 */
        reas_data_entry = &reas_data[i];
        reas_data_entry->hash = hash;
        pkt_seg = &reas_data_entry->seg[0];
        pkt_seg->offset = pkt->pkt.data_len - sizeof(struct ipv4_hdr) -
            sizeof(struct udp_hdr);
        pkt_seg->pkt = pkt;
        pkt_seg->seg = seg;
        reas_data_entry->next_expected_seq = pkt_seg->seg->pkt.data_len -
            sizeof(struct ipv4_hdr) -
            sizeof(struct udp_hdr);
        reas_data_entry->nb_seg = 1;
    }
    return -1;
}

int main(int argc, char **argv) {
    int ret;
    uint8_t portid = 0;
    struct rte_mbuf *pkts_burst[MAX_PKT_BURST];

    /* 初始化EAL以及DPDK */
    ret = rte_eal_init(argc, argv);
    if (ret < 0)
        rte_panic("Cannot init EAL\n");
    argc -= ret;
    argv += ret;
    ret = rte_pmd_init_all();
    if (ret < 0)
        rte_exit(EXIT_FAILURE, "Cannot init pmds\n");
    /* 初始化由RTE mempool分配的缓存池 */
    init_mbuf_pool();

    while (1) {
        uint16_t nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst, MAX_PKT_BURST);
        for (int i = 0; i < nb_rx; i++) {
            struct rte_mbuf *pkt = pkts_burst[i];
            if (pkt->pkt.nb_segs > 1) {
                /* 大于MTU的报文分片 */
                uint32_t ret = cache_reassemble_packet(pkt, pkt->pkt.next);
                if (ret > 0) {
                    /* 如果ret的值大于0,则说明重组成功,传递给网络协议栈 */
                    continue;
                } else if (ret == 0) {
                    rte_pktmbuf_free(pkt);
                    continue;
                }
            }
            /* 如果不需要缓存/重组,则将数据包传递给协议栈 */
            eth_protocol_handler(pkt);
        }
    }
    return 0;
}

值得注意的是,DPDK的分片重组需要耗费大量的CPU和内存资源,因此在设计DPDK应用程序时应该仔细考虑内存和CPU的使用情况,以确保应用程序的高性能和稳定性。

Dpdk/网络协议栈/vpp/OvS/DDos/NFV  视频教程学习地址: https://ke.qq.com/course/5066203?flowToken=1043068
DPDK/网络虚拟化 相关学习资料、视频教程 学习群:739729163 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值