ZBLOG

dpdk分片重组的代码

以下是基于DPDK的简单分片重组示例代码:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_mbuf.h>

#define MAX_PKT_BURST 32
#define MAX_FRAGMENTS 4

struct ipv4_hdr {
    uint8_t version_ihl;
    uint8_t type_of_service;
    uint16_t total_length;
    uint16_t packet_id;
    uint16_t fragment_offset;
    uint8_t time_to_live;
    uint8_t next_proto_id;
    uint16_t hdr_checksum;
    uint32_t src_addr;
    uint32_t dst_addr;
} __attribute__((__packed__));

static struct rte_mempool *pktmbuf_pool;

// Helper function to calculate the IPv4 header checksum
static inline void ipv4_hdr_cksum(struct ipv4_hdr *hdr) {
    hdr->hdr_checksum = 0;

    int len = (hdr->version_ihl & 0x0F) << 2; // Length of the IPv4 header in bytes
    uint32_t sum = 0;

    for (int i = 0; i < len; i += 2)
        sum += ((uint16_t *)hdr)[i / 2];

    while (sum >> 16)
        sum = (sum & 0xFFFF) + (sum >> 16);

    hdr->hdr_checksum = ~sum;
}

// Function to reassemble fragmented packets
static void reassemble_packet(struct rte_mbuf **fragments, int num_fragments) {
    struct ipv4_hdr *first_frag_hdr = rte_pktmbuf_mtod(fragments[0], struct ipv4_hdr *);
    
    if ((first_frag_hdr->fragment_offset & htons(0x1FFF)) != 0) {
        // The first fragment doesn't have a zero offset, so it's not the first fragment
        printf("Error: not the first fragment\n");
        return;
    }
    
    int total_length = ntohs(first_frag_hdr->total_length);
    int hdr_len = (first_frag_hdr->version_ihl & 0x0F) << 2;
    int payload_len = total_length - hdr_len;
    
    if (payload_len > (num_fragments - 1) * rte_pktmbuf_data_room_size()) {
        // The reassembled packet would be too large to fit in one mbuf
        printf("Error: packet too large\n");
        return;
    }
    
    struct rte_mbuf *pkt = rte_pktmbuf_alloc(pktmbuf_pool);
    
    if (!pkt) {
        printf("Error: could not allocate mbuf for reassembled packet\n");
        return;
    }
    
    uint8_t *pkt_data = rte_pktmbuf_mtod(pkt, uint8_t *);
    
    memcpy(pkt_data, rte_pktmbuf_mtod(fragments[0], void *), hdr_len); // Copy the header
    
    uint8_t *payload_ptr = pkt_data + hdr_len; // Pointer to the start of the payload
    int payload_bytes_copied = 0; // Number of bytes of payload copied so far
    
    for (int i = 0; i < num_fragments; i++) {
        struct ipv4_hdr *frag_hdr = rte_pktmbuf_mtod(fragments[i], struct ipv4_hdr *);
        
        if ((frag_hdr->fragment_offset & htons(0x1FFF)) != (i * MAX_FRAGMENTS)) {
            // This is not the correct offset for this fragment
            printf("Error: incorrect fragment offset\n");
            rte_pktmbuf_free(pkt);
            return;
        }
        
        int frag_payload_len = ntohs(frag_hdr->total_length) - ((frag_hdr->version_ihl & 0x0F) << 2);
        uint8_t *frag_payload_ptr = rte_pktmbuf_mtod_offset(fragments[i], uint8_t *, (frag_hdr->version_ihl & 0x0F) << 2); // Pointer to the start of the payload in this fragment
        
        memcpy(payload_ptr, frag_payload_ptr, frag_payload_len); // Copy the payload from this fragment
        
        payload_bytes_copied += frag_payload_len;
        
        if (payload_bytes_copied >= payload_len)
            break; // We've copied all the payload bytes we need
    }
    
    pkt->pkt_len = total_length;
    pkt->data_len = total_length;
    
    ipv4_hdr_cksum((struct ipv4_hdr *)pkt_data); // Recalculate the checksum
    
    printf("Reassembled packet with ID %d\n", ntohs(first_frag_hdr->packet_id));
}

int main(int argc, char *argv[]) {
    int ret = rte_eal_init(argc, argv);

    if (ret < 0)
        return -1;

    argc -= ret;
    argv += ret;

    if (argc != 3) {
        printf("Usage: %s <port_id> <num_queues>\n", argv[0]);
        return -1;
    }

    uint16_t port_id = atoi(argv[1]);
    uint16_t num_queues = atoi(argv[2]);

    if (!rte_eth_dev_is_valid_port(port_id)) {
        printf("Error: invalid port number\n");
        return -1;
    }

    pktmbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", 8192,
        32 /* cache size */, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());

    if (!pktmbuf_pool) {
        printf("Error: could not create mbuf pool\n");
        return -1;
    }

    ret = rte_eth_dev_configure(port_id, num_queues, num_queues, NULL);

    if (ret < 0) {
        printf("Error: could not configure port %u\n", port_id);
        return -1;
    }

    for (int i = 0; i < num_queues; i++) {
        ret = rte_eth_rx_queue_setup(port_id, i, MAX_PKT_BURST,
            rte_eth_dev_socket_id(port_id), NULL, pktmbuf_pool);

        if (ret < 0) {
            printf("Error: could not setup RX queue %d on port %u\n", i, port_id);
            return -1;
        }
    }

    ret = rte_eth_dev_start(port_id);

    if (ret < 0) {
        printf("Error: could not start port %u\n", port_id);
        return -1;
    }

    struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
    
    while (1) {
        for (int qid = 0; qid < num_queues; qid++) {
            int num_rx = rte_eth_rx_burst(port_id, qid, pkts_burst, MAX_PKT_BURST);
            
            for (int i = 0; i < num_rx; i++) {
                struct ipv4_hdr *ipv4_hdr = rte_pktmbuf_mtod_offset(pkts_burst[i], struct ipv4_hdr *, sizeof(struct ether_hdr));
                
                if ((ipv4_hdr->version_ihl >> 4) != 4 || ipv4_hdr->next_proto_id != IPPROTO_UDP)
                    continue; // Not an IPv4 or UDP packet
                
                int num_frags = (ntohs(ipv4_hdr->total_length) - sizeof(struct ipv4_hdr)) / rte_pktmbuf_data_room_size() + 1;
                
                if (num_frags <= 1)
                    continue; // Not a fragmented packet
                
                struct rte_mbuf *fragments[MAX_FRAGMENTS];
                
                for (int j = 0; j < num_frags; j++) {
                    fragments[j] = rte_pktmbuf_alloc(pktmbuf_pool);
                    
                    if (!fragments[j]) {
                        printf("Error: could not allocate mbuf for fragment\n");
                        
                        for (int k = 0; k < j; k++)
                            rte_pktmbuf_free(fragments[k]);
                        
                        goto next_packet;
                    }
                    
                    uint8_t *pkt_data = rte_pktmbuf_mtod(pkts_burst[i], uint8_t *);
                    uint32_t frag_offset = ((uint16_t)(pkt_data[6]) << 8) | pkt_data[7]; // Offset in bytes from the start of the original packet
                    uint32_t frag_len = ntohs(((uint16_t *)(ipv4_hdr + 1))[j]); // Length of this fragment's payload
                    
                    memcpy(rte_pktmbuf_mtod(fragments[j], void *), pkt_data + sizeof(struct ipv4_hdr) + frag_offset, frag_len); // Copy the payload from the original packet
                    
                    struct ipv4_hdr *frag_hdr = rte_pktmbuf_mtod(fragments[j], struct ipv4_hdr *);
                    
                    frag_hdr->fragment_offset &= htons(0xE000); // Clear lower 13 bits of fragment offset
                    frag_hdr->fragment_offset |= htons(j * MAX_FRAGMENTS); // Set the correct fragment offset for this fragment
                    
                    ipv4_hdr_cksum(frag_hdr); // Recalculate the checksum
                    
                    fragments[j]->pkt_len = sizeof(struct ipv4_hdr) + frag_len;
                    fragments[j]->data_len = sizeof(struct ipv4_hdr) + frag_len;
                }
                
                reassemble_packet(fragments, num_frags);
                
                next_packet:
                rte_pktmbuf_free(pkts_burst[i]);
            }
        }
    }

    return 0;
}

该示例代码包含以下几个关键部分:

  1. reassemble_packet函数:用于将分片重组成原始数据包。该函数需要接收一个指向所有碎片的rte_mbuf结构体的指针数组以及碎片数作为参数,并返回重新组装后的完整数据包。

  2. 在主循环中,从DPDK驱动程序中接收分组并检查它们是否是IPV4和UDP协议。如果它们是分段的,则使用reassemble_packet函数将它们重组回完整的数据包。

  3. ipv4_hdr_cksum函数:用于计算IPv4头校验和。

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=739

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?