Anoop C
Anoop C

Reputation: 35

Receiving Duplicate packets in receiver side when played through DPDK

I have a scenario where i am trying to send packets from a pcap file using dpdk to other other port connected by loopback cable,

Issue: Getting Duplicate packets instead of different ones on receiver side

C-Program:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <netinet/in.h>
#include <time.h>
#include <pcap.h>

#include <inttypes.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>

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

#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
#define NB_MBUF (1024 * 8)

#define ETH_PORT_ID 0 // Modify this according to your environment

long long int pcap_time_concat(const struct pcap_pkthdr *header) {
    // Implement your concat function
    // This function is assumed to concatenate timestamp seconds and microseconds
    // into a single long long int value
    return header->ts.tv_sec * 1000000000LL + header->ts.tv_usec;
}

long long int system_time_concat(long sec, long nsec) {
    // Convert seconds to nanoseconds and add the nanoseconds
    long long int result = sec * 1000000000LL + nsec;
    return result;
}

static inline int
port_init(uint16_t port, struct rte_mempool *mbuf_pool)
{
    struct rte_eth_conf port_conf;
    const uint16_t rx_rings = 1, tx_rings = 1;
    uint16_t nb_rxd = RX_RING_SIZE;
    uint16_t nb_txd = TX_RING_SIZE;
    int retval;
    uint16_t q;
    struct rte_eth_dev_info dev_info;
    struct rte_eth_txconf txconf;

    if (!rte_eth_dev_is_valid_port(port))
        return -1;

    memset(&port_conf, 0, sizeof(struct rte_eth_conf));

    retval = rte_eth_dev_info_get(port, &dev_info);
    if (retval != 0)
    {
        printf("Error during getting device (port %u) info: %s\n",
               port, strerror(-retval));
        return retval;
    }

    if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
        port_conf.txmode.offloads |=
            RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;

    /* Configure the Ethernet device. */
    retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
    if (retval != 0)
        return retval;

    retval = rte_eth_dev_set_mtu(port, 9000);
    if (retval != 0)
        return retval;

    retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
    if (retval != 0)
        return retval;

    /* Allocate and set up 1 RX queue per Ethernet port. */
    for (q = 0; q < rx_rings; q++)
    {
        retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
                                        rte_eth_dev_socket_id(port), NULL, mbuf_pool);
        if (retval < 0)
            return retval;
    }

    txconf = dev_info.default_txconf;
    txconf.offloads = port_conf.txmode.offloads;
    /* Allocate and set up 1 TX queue per Ethernet port. */
    for (q = 0; q < tx_rings; q++)
    {
        retval = rte_eth_tx_queue_setup(port, q, nb_txd,
                                        rte_eth_dev_socket_id(port), &txconf);
        if (retval < 0)
            return retval;
    }

    /* Starting Ethernet port. 8< */
    retval = rte_eth_dev_start(port);
    /* >8 End of starting of ethernet port. */
    if (retval < 0)
        return retval;

    /* Display the port MAC address. */
    struct rte_ether_addr addr;
    retval = rte_eth_macaddr_get(port, &addr);
    if (retval != 0)
        return retval;

    printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
           " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
           port, RTE_ETHER_ADDR_BYTES(&addr));

    /* Enable RX in promiscuous mode for the Ethernet device. */
    retval = rte_eth_promiscuous_enable(port);
    /* End of setting RX port in promiscuous mode. */
    if (retval != 0)
        return retval;

    return 0;
}

static struct rte_mempool *mbuf_pool1;

int main(int argc, char *argv[])
{
    // Initialize DPDK
    int ret = rte_eal_init(argc, argv);
    uint16_t portid;
    struct rte_mempool *mbuf_pool;
    struct timespec system_time;
    if (ret < 0)
    {
        rte_exit(EXIT_FAILURE, "Error initializing DPDK\n");
    }

    // Open Ethernet device
    if (rte_eth_dev_count_avail() == 0)
    {
        rte_exit(EXIT_FAILURE, "No Ethernet ports found\n");
    }

    // Assuming only one port is available
    mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * 1,
                                        MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
    RTE_ETH_FOREACH_DEV(portid)
    if (port_init(portid, mbuf_pool) != 0)
        rte_exit(EXIT_FAILURE, "Cannot init port %" PRIu16 "\n",
                 portid);

    pcap_t *pcap;
    char errbuf[PCAP_ERRBUF_SIZE];

    // Open pcap file
    // pcap = pcap_open_offline("c2_15scs_4_ant_256_frame_128.pcap", errbuf);
    // pcap = pcap_open_offline("TM3.1a_1CC_CC0_8ant_1Slot.pcap", errbuf);
    pcap_t *handle = pcap_open_offline_with_tstamp_precision(argv[1], PCAP_TSTAMP_PRECISION_NANO, errbuf);
    // pcap_t *handle = pcap_open_offline_with_tstamp_precision("c2_15scs_4_ant_256_frame_128.pcap", PCAP_TSTAMP_PRECISION_NANO, errbuf);
    if (handle == NULL) {
        fprintf(stderr, "pcap_open_offline_with_tstamp_precision failed: %s\n", errbuf);
        return 1;
    }

    // Main loop for reading packets and sending them
    const struct pcap_pkthdr header;
    const u_char *packet;
    uint8_t tx_port = portid;
    struct rte_mbuf *mbufs[1];
    mbuf_pool1 = rte_pktmbuf_pool_create("MBUF_POOL1", NB_MBUF, 32,
                                         0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_eth_dev_socket_id(0));
    int packetCount = 1;
    int readstat = 1;
    long long int packet_epoch_time = 0;
    long long int emul_ref_time = -1;
    long long int emul_ref_time_tod = -1;
    long long int epoch_ref_time = -1;
    long long int delta_time = 0;
    long long int current_emul_time = -1;

    packet = pcap_next(handle, &header);
    if (packet == NULL) {
        printf("End of file reached or error occurred while reading packet.\n");
    }
    packet_epoch_time = pcap_time_concat(&header);

    for (int i = 0; i > -1; i++) 
    {

        if (packet == NULL) {
            printf("End of file reached or error occurred while reading packet.\n");
            break;
        }
        if(i == 0)
        {
            clock_gettime(CLOCK_REALTIME, &system_time);
            emul_ref_time = system_time_concat(system_time.tv_sec, system_time.tv_nsec);
            // printf("\n emul_ref_time: %lld\n", emul_ref_time);
            mbufs[0] = rte_pktmbuf_alloc(mbuf_pool1);
            if (mbufs[0] == NULL)
            {
                rte_exit(EXIT_FAILURE, "Failed to allocate mbuf\n");
            }
            rte_memcpy(rte_pktmbuf_mtod(mbufs[0], void *), packet, header.len);
            // rte_memcpy((char*)mbufs[0]->buf_addr, packet, header.len);
            // printf("\npacket: %p\n", (char *)packet);
            mbufs[0]->data_len = header.caplen;
            mbufs[0]->pkt_len = header.len;
            rte_pktmbuf_dump(stdout, mbufs[0], rte_pktmbuf_pkt_len(mbufs[0]));
            int sent = rte_eth_tx_burst(0, 0, mbufs, 1);
            if(!sent)
            {
                rte_exit(EXIT_FAILURE, "Failed to Send Packet\n");
            }
            epoch_ref_time = pcap_time_concat(&header);
            // printf("\n epoch_ref_time: %lld\n", epoch_ref_time);
            packet = pcap_next(handle, &header);
            packet_epoch_time = pcap_time_concat(&header);
            // printf("\n packet_epoch_time: %lld\n", packet_epoch_time);
            rte_pktmbuf_free(mbufs[0]);
        }
        if ((packet_epoch_time - 5100) <= current_emul_time && current_emul_time <= (packet_epoch_time + 5100)) // Transmit Subsequent packets of the respective port when matches time window.
        {
            mbufs[0] = rte_pktmbuf_alloc(mbuf_pool1);
            if (mbufs[0] == NULL)
            {
                rte_exit(EXIT_FAILURE, "Failed to allocate mbuf\n");
            }
            rte_memcpy(rte_pktmbuf_mtod(mbufs[0], void *), packet, header.len);
            // rte_memcpy((char*)mbufs[0]->buf_addr, packet, header.len);
            // printf("\npacket: %p\n", (char *)packet);
            mbufs[0]->data_len = header.caplen;
            mbufs[0]->pkt_len = header.len;
            rte_pktmbuf_dump(stdout, mbufs[0], rte_pktmbuf_pkt_len(mbufs[0]));
            int sent = rte_eth_tx_burst(0, 0, mbufs, 1);
            if(!sent)
            {
                rte_exit(EXIT_FAILURE, "Failed to Send Packet\n");
            }
            packetCount++;
            printf("%d packet sent\n", packetCount);
            packet = pcap_next(handle, &header);
            packet_epoch_time = pcap_time_concat(&header);
            rte_pktmbuf_free(mbufs[0]);
            break;
        }
        else if (current_emul_time > (packet_epoch_time + 5100))
        {
            mbufs[0] = rte_pktmbuf_alloc(mbuf_pool1);
            if (mbufs[0] == NULL)
            {
                rte_exit(EXIT_FAILURE, "Failed to allocate mbuf\n");
            }
            rte_memcpy(rte_pktmbuf_mtod(mbufs[0], void *), packet, header.len);
            // rte_memcpy((char*)mbufs[0]->buf_addr, packet, header.len);
            // printf("\npacket: %p\n", (char *)packet);
            mbufs[0]->data_len = header.caplen;
            mbufs[0]->pkt_len = header.len;
            rte_pktmbuf_dump(stdout, mbufs[0], rte_pktmbuf_pkt_len(mbufs[0]));
            int sent = rte_eth_tx_burst(0, 0, mbufs, 1);
            if(!sent)
            {
                rte_exit(EXIT_FAILURE, "Failed to Send Packet\n");
            }
            packetCount++;
            printf("%d frag packet sent, diff_time: %lld\n", packetCount, current_emul_time - (packet_epoch_time + 5100));
            packet = pcap_next(handle, &header);
            packet_epoch_time = pcap_time_concat(&header);
            rte_pktmbuf_free(mbufs[0]);
            break;
        }
        if (epoch_ref_time != -1)
        {
            //gettimeofday(&loop_time, NULL);
            clock_gettime(CLOCK_REALTIME, &system_time);
            long long int temp_current_time = system_time_concat(system_time.tv_sec, system_time.tv_nsec);
            //long long int temp_current_time_tod = system_time_concat(loop_time.tv_sec, loop_time.tv_usec);
            // delta_time = (loop_time.tv_usec - emul_ref_time)*1000;
            //printf("\n system_time: %lld.%lld\n", system_time.tv_sec, system_time.tv_nsec);
            // printf("\n temp_current_time: %lld\n", temp_current_time);
            //printf("\n temp_current_time_tod: %lld\n", temp_current_time_tod);
            delta_time = temp_current_time - emul_ref_time;
            // printf("\n delta_time: %lld\n", delta_time);
            current_emul_time = epoch_ref_time + delta_time;
            // printf("\n current_emul_time: %lld\n", current_emul_time);
        }
        
    }
    pcap_close(handle);
    rte_eth_dev_stop(0);
    rte_eth_dev_close(0);
    rte_eal_cleanup();

    return 0;
}

In the above code i just tested the sending two packets and see in the receiver side

Transmitting Side: rte_pktmbuf_dump of the mbufs[0] prints two different packets enter image description here

Receiver Side: tcpdump of incoming packets Getting the second packet transmitted twice on receiver side and there is no first packet at all enter image description here

Please help me to figure out the issue, if i add delay in the for loop then i don`t see the duplicate packets

Upvotes: 1

Views: 72

Answers (0)

Related Questions