能够基于dpdk19.11进行L4处理的c程序

环境:dpdk19.11 ubuntu-18.04.5

两台ubuntu机器,一台基于dpdk进行L4处理(tcp/udp/icmp),另一台作为对端正常使用

求一套可以使用的基于dpdk19.11进行L4处理的c程序代码,
使用igb_uio或者vfio驱动,程序能够收发tcp/udp包、有自定义建立tcp/udp的套接字。
能够与未绑定dpdk驱动的对端电脑,互相进行tcp/udp连接、ping。

send.c

#include <stdio.h>
#include <arpa/inet.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_mbuf.h>

#define NUM_MBUFS        (4096-1)
#define MBUFS_SIZE        32
#define ENABLE_SEND        1

uint16_t port_id = 0;



#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



static const struct rte_eth_conf port_conf_default = {
    .rxmode = {.max_rx_pkt_len = RTE_ETHER_MAX_LEN }
};

static void init_port(struct rte_mempool *mbufpool)
{
    /*Get the number of ports which are usable for the application.*/
    uint16_t sys_port = rte_eth_dev_count_avail();
    if(sys_port == 0){
        rte_exit(EXIT_FAILURE, "Not available eth\n");
    }

    /*Get ethernet information*/
    struct rte_eth_dev_info dev_info;
    rte_eth_dev_info_get(port_id, &dev_info);

    /*Configure an Ethernet device*/
    uint16_t nb_rx_q = 1;
    uint16_t nb_tx_q = 1;
    struct rte_eth_conf dev_conf = port_conf_default;
    rte_eth_dev_configure(port_id, nb_rx_q, nb_tx_q, &dev_conf);

    /*Allocate and set up a receive queue for an Ethernet device*/
    uint16_t rx_queue_id = nb_rx_q - 1;
    unsigned int socket_id = rte_eth_dev_socket_id(port_id);
    if(rte_eth_rx_queue_setup(port_id, rx_queue_id, 1024, socket_id, NULL, mbufpool) < 0)
        rte_exit(EXIT_FAILURE, "Receive queue error\n");
        
#if ENABLE_SEND
    /*Allocate and set up a transmit queue for an Ethernet device*/
    struct rte_eth_txconf txq_conf = dev_info.default_txconf;
    txq_conf.offloads = dev_conf.rxmode.offloads;
    if (rte_eth_tx_queue_setup(port_id, 0 , 1024, socket_id, &txq_conf) < 0)
        rte_exit(EXIT_FAILURE, "Could not setup TX queue\n");

#endif

    /*Start an Ethernet device*/
    if(rte_eth_dev_start(port_id) < 0)
        rte_exit(EXIT_FAILURE, "Start ethernet error\n");

}



int main(int argc, char **argv)
{
    unsigned int i =0;
    //uint8_t   au8SendMsg[] = "hello misss";
    
    /*init*/
    if(rte_eal_init(argc, argv) < 0)
        rte_exit(EXIT_FAILURE, "EAL init Error\n");

    /*create a mbuf pool*/
    struct rte_mempool *mbufpool = rte_pktmbuf_pool_create("mbufpool", NUM_MBUFS, 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
    if(mbufpool == NULL)
        rte_exit(EXIT_FAILURE, "Create mbufpool Error\n");

    /*init port*/
    init_port(mbufpool);


    rte_eth_macaddr_get(port_id, (struct rte_ether_addr *)gSrcMac);

    while(1){
        struct rte_mbuf *rx_pkts[MBUFS_SIZE];
        /*Retrieve a burst of input packets from a receive queue of an Ethernet device*/
        unsigned num_recv = rte_eth_rx_burst(port_id, 0, rx_pkts, MBUFS_SIZE);
        if(num_recv > MBUFS_SIZE)
            rte_exit(EXIT_FAILURE, "Receive from eth error\n");

        for(i = 0; i < num_recv; i++){
            
            struct rte_ether_hdr *ehdr  = rte_pktmbuf_mtod(rx_pkts[i], struct rte_ether_hdr*);
            if (ehdr->ether_type != rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
                rte_pktmbuf_free(rx_pkts[i]);
                continue;
            }
            
            struct rte_ipv4_hdr *iphdr =  rte_pktmbuf_mtod_offset(rx_pkts[i], struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr));
            if (iphdr->next_proto_id == IPPROTO_UDP) {
                /*IPPROTO_UDP is defined in kernel source code include/uapi/inux/in.h*/

                struct rte_udp_hdr *udphdr = (struct rte_udp_hdr *)(iphdr + 1);

#if ENABLE_SEND

                //rte_eth_macaddr_get(port_id, (struct rte_ether_addr *)gSrcMac);
                rte_memcpy(gDstMac, ehdr->s_addr.addr_bytes, RTE_ETHER_ADDR_LEN);
                                
                rte_memcpy(&gSrcIp, &iphdr->dst_addr, sizeof(uint32_t));
                rte_memcpy(&gDstIp, &iphdr->src_addr, sizeof(uint32_t));
                
                rte_memcpy(&gSrcPort, &udphdr->dst_port, sizeof(uint16_t));
                rte_memcpy(&gDstPort, &udphdr->src_port, sizeof(uint16_t));
            
#endif

                uint16_t length = ntohs(udphdr->dgram_len);
                *((char*)udphdr + length) = '\0';

                struct in_addr addr;
                addr.s_addr = iphdr->src_addr;
                printf("<- src: %s:%d, ", inet_ntoa(addr), udphdr->src_port);
                addr.s_addr = iphdr->dst_addr;
                printf("dst: %s:%d, %s\n", inet_ntoa(addr), udphdr->dst_port, (char *)(udphdr+1));
                
#if ENABLE_SEND
                //20220926add
                rte_memcpy(&iphdr->src_addr, &gSrcIp, sizeof(uint32_t));
                rte_memcpy(&iphdr->dst_addr, &gDstIp, sizeof(uint32_t));
                addr.s_addr = iphdr->src_addr;
                printf("-> src: %s:%d, ", inet_ntoa(addr), udphdr->src_port);
                addr.s_addr = iphdr->dst_addr;
                printf("dst: %s:%d, %s\n", inet_ntoa(addr), udphdr->dst_port, (char *)(udphdr+1));

                rte_memcpy(ehdr->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
                rte_memcpy(ehdr->d_addr.addr_bytes, gDstMac, RTE_ETHER_ADDR_LEN);
                
                //调测增加,实际使用可去掉端口限制
                if (4369 == udphdr->src_port)
                {
                    rte_eth_tx_burst(port_id , 0, rx_pkts, num_recv);
                                  
                }
#endif
                rte_pktmbuf_free(rx_pkts[i]);
            }
        }
    }
}