在linux中低速发送数据包

时间:2013-05-22 17:06:33

标签: linux network-programming linux-kernel

最近致力于一个以高速率(超过500Mbitps)转发数据包的项目。我尝试了2种方法,但它们不起作用。 主机是vm,ubuntu-11.10 32bit,nic是r8169,1000Mb。

  1. 我使用带有buff的原始袜子,其大小取决于收到的数据包的大小(不超过1500)。我把sendto函数放在循环中(while(1)),确保它可以尽可能快地发送。但发送速度远低于r8169的速度,它大约是100-200Mbitps。我可以认为套接字无法进行高速发送吗?但为什么像Iperf以及使用套接字可以表现更好?或者我能做些什么来加快发送速度?

  2. 我在内核中使用了dev_queue_xmit()。我把函数放在一个循环中(while(1))在一个带有schedule()的kthread中。但发送速度不超过300Mbitps。我知道调用dev_queue_xmit可能不是一个好主意,但我仍然不明白为什么速度这么低?

  3. 请,需要帮助..

    或者任何人都可以为我提供高速转发数据包的经典解决方案? 我的套接字很简单:

    int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP)/*IPPROTO_RAW*/);
    struct ifreq if_idx;
    char ifName[IFNAMSIZ];
    struct sockaddr_ll socket_address;
    char buf[1400];
    struct packet_mreq mr;
    struct ether_header *eh;
    int ret = 0;
    struct ifreq if_mac;
    
    strcpy(ifName, "eth1");//used for sending
    memset(&if_idx, 0, sizeof(struct ifreq));
    strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);
    if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
        perror("SIOCGIFINDEX\n");
    memset(&if_mac, 0, sizeof(struct ifreq));
    strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
    if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
        perror("SIOCGIFHWADDR\n");
    
    socket_address.sll_ifindex = if_idx.ifr_ifindex;
    /* Address length*/
    socket_address.sll_halen = ETH_ALEN;
    /* Destination MAC */
    socket_address.sll_family = AF_PACKET;
    socket_address.sll_protocol = htons(0xA000);
    socket_address.sll_addr[0] = 0x00;
    socket_address.sll_addr[1] = 0x24;
    socket_address.sll_addr[2] = 0xe8;
    socket_address.sll_addr[3] = 0x82;
    socket_address.sll_addr[4] = 0xec;
    socket_address.sll_addr[5] = 0x82;
    printf("%d\n",bind(sockfd, (struct sockaddr *) &socket_address, sizeof(socket_address))); 
    
    memset (&mr, 0, sizeof(mr));
    mr.mr_ifindex = if_idx.ifr_ifindex;
    //mr.mr_type = PACKET_MR_PROMISC;
    setsockopt(sockfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr,sizeof(mr));
    
    eh = (struct ether_header *)buf;
    eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
    eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
    eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
    eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
    eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
    eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
    eh->ether_dhost[0] = 0x00;
    eh->ether_dhost[1] = 0x24;
    eh->ether_dhost[2] = 0xe8;
    eh->ether_dhost[3] = 0x82;
    eh->ether_dhost[4] = 0xec;
    eh->ether_dhost[5] = 0x82;
    eh->ether_type = htons(0xA000);
    while(1)
        ret = write(sockfd,buf,1000);
    printf("%d\n",ret);
    return 0;
    

1 个答案:

答案 0 :(得分:0)

您是否看过writev(),它允许您提供多个缓冲区?您是从文件中获取数据吗?如果是这样,您可能需要调查sendfile()。