相关代码:DPDK_Learning/UDP_transmit at main · mfdycs/DPDK_Learning (github.com)

DPDK启动逻辑框架可以参考 接收UDP数据

定义网络信息

400

#define ENABLE_SEND 1  
#define ENABLE_ARP  1

// 发送数据需要的网络信息, 先不考虑传参  
#if ENABLE_SEND  

static uint32_t gSrcIp;  
static uint32_t gDstIp;  

static uint8_t gSrcMac[RTE_ETHER_ADDR_LEN];  
static uint8_t gDstMac[RTE_ETHER_ADDR_LEN];  

static uint16_t gSrcPort;  
static uint16_t gDstPort;  

#endif

启动发送队列

// 配置网卡信息   
const int num_tx_queues = 1; // 发送队列网卡数量  
struct rte_eth_conf port_conf = port_conf_default;  

#if ENABLE_SEND  
    // 启动tx队列  
    struct rte_eth_txconf txq_conf = dev_info.default_txconf;  
    // 修改tx对应负载:把发送大小设置为接收大小  
    txq_conf.offloads = port_conf.rxmode.offloads;  

    // rte_eth_tx_queue_setup(port_id, tx_queue_id, nb_rx_desc, socket_id, tx_conf);  
    ret = rte_eth_tx_queue_setup(DPDK_PortID, 0, 128, rte_eth_dev_socket_id(DPDK_PortID), &txq_conf);  
    if (ret < 0) {  
        rte_exit(EXIT_FAILURE, "Could not setup TX queue\n");  
    }  
#endif

发送数据

从 mempool 里面获取到 mbuf,mbuf是内存池中的最小单元

UDP首部长度为42字节:14(eth) + 20(ip) + 8(udp)

static struct rte_mbuf* ng_send(struct rte_mempool *mbuf_pool, unsigned char* data, uint16_t length)  
{  
    struct rte_mbuf* mbuf = rte_pktmbuf_alloc(mbuf_pool);  
    if (!mbuf) {  
        rte_exit(EXIT_FAILURE, "Error with EAL init\n");  
    }  
    mbuf->pkt_len = total_len;  
    mbuf->data_len = total_len; 
   uint8_t *pktdata = rte_pktmbuf_mtod(mbuf, uint8_t*);  

    ng_encode_udp_pkt(pktdata, data, total_len);  

    return mbuf; 
}

封装UDP数据

UDP数据头部信息:
|500

以太网协议头:
|500

IP协议头:
|500

// encode udp pkt  
static int ng_encode_udp_pkt(uint8_t *msg, unsigned char* data, uint16_t total_len)
{
    // 1. ethhdr
    struct rte_ether_hdr* eth = (struct rte_ether_hdr*)msg;
    rte_memcpy(eth->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
    rte_memcpy(eth->d_addr.addr_bytes, gDstMac, RTE_ETHER_ADDR_LEN);
    eth->ether_type = htons(RTE_ETHER_TYPE_IPV4); 

    // 2. iphdr
    struct rte_ipv4_hdr* ip = (struct rte_ipv4_hdr*)(msg + sizeof(struct rte_ether_hdr));
    ip->version_ihl = 0x54; // 版本+首部长度信息, 网络字节序
    ip->type_of_service = 0;
    ip->total_length = htons(total_len - sizeof(struct rte_ether_hdr));
    ip->packet_id = 0; // 16位位标识
    ip->fragment_offset = 0; // 3位标识+13位片位移
    ip->time_to_live = 64;
    ip->next_proto_id = IPPROTO_UDP;
    ip->src_addr = gSrcIp;
    ip->dst_addr = gDstIp;

    ip->hdr_checksum = 0; // 先置0, 因为会参与计算
    ip->hdr_checksum = rte_ipv4_cksum(ip);

    // 3. udphdr
    struct rte_udp_hdr* udp = (struct rte_udp_hdr*)(msg + sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
    udp->src_port = gSrcPort;
    udp->dst_port = gDstPort;
    uint16_t udplen = total_len - sizeof(struct rte_ether_hdr) - sizeof(struct rte_ipv4_hdr);
    udp->dgram_len = htons(udplen);

    rte_memcpy((uint8_t*)(udp + 1), data, udplen);

    udp->dgram_cksum = 0;
    udp->dgram_cksum = rte_ipv4_udptcp_cksum(ip, udp);

    // 4. print
    struct in_addr addr;
    addr.s_addr = gSrcIp;
    printf(" --> src: %s:%d, ", inet_ntoa(addr), ntohs(gSrcPort));

    addr.s_addr = gDstIp;
    printf("dst: %s:%d\n", inet_ntoa(addr), ntohs(gDstPort));

    return 0;
}

static struct rte_mbuf* ng_send(struct rte_mempool *mbuf_pool, unsigned char* data, uint16_t length)
{
    const unsigned total_len = length + 42;


    struct rte_mbuf* mbuf =  rte_pktmbuf_alloc(mbuf_pool);
    if (!mbuf) {
        rte_exit(EXIT_FAILURE, "Error with EAL init\n");
    }
    mbuf->pkt_len = total_len;
    mbuf->data_len = total_len;

    uint8_t *pktdata = rte_pktmbuf_mtod(mbuf, uint8_t*);

    ng_encode_udp_pkt(pktdata, data, total_len);

    return mbuf;
}