首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我们的数据包嗅探器不能接收所有重放的TCP数据包?

为什么我们的数据包嗅探器不能接收所有重放的TCP数据包?
EN

Stack Overflow用户
提问于 2015-03-20 03:49:39
回答 1查看 1.6K关注 0票数 0

我们试图使用tcpreplay在10 GbE连接上重放一个pcap (pcap,smallFlows.pcap),并捕获所有数据包,记录源端口和目标端口/IP地址。然而,存在着显著的分组丢失。在3 Gbps,我们正在失去约15%的数据包发送。即使是1 Gbps,我们也在亏损7%。我们的嗅探器程序是用netmap-libpcap用C编写的,是sniffex.c的一个修改版本。

我们在测试时删除了所有的打印语句。我们试图改变快照长度和缓冲区大小,但这只是稍微提高了数据包丢失率。我们还将发送端和接收端上的CPU核心设置为性能模式,以最大限度地提高时钟速度(接收端大约为2.67 GHz ),但这没有任何影响。据托普说,CPU使用率相当低--约为15%。

接收器有一个英特尔核心i7处理器。发送方运行Ubuntu12.04.3LTS (linux内核3.8.13),接收方运行Ubuntu12.04 (linux内核3.2.023-泛型)。

我们能做些什么来确保所有的数据包被接收?

以下是主要功能:

代码语言:javascript
复制
int main(int argc, char **argv)
{

  char *dev = NULL;         /* capture device name */
  char errbuf[PCAP_ERRBUF_SIZE];        /* error buffer */
  pcap_t *handle;               /* packet capture handle */

  char filter_exp[] = "ip";     /* filter expression [3] */
  bpf_u_int32 mask;         /* subnet mask */
  bpf_u_int32 net;          /* ip */
  int num_packets = 10;         /* number of packets to capture */

  print_app_banner();
  printf(pcap_lib_version());
  /* check for capture device name on command-line */
  if (argc == 2) {
    dev = argv[1];
  }
  else if (argc > 2) {
    fprintf(stderr, "error: unrecognized command-line options\n\n");
    print_app_usage();
    exit(EXIT_FAILURE);
  }
  else {
    /* find a capture device if not specified on command-line */
    dev = pcap_lookupdev(errbuf);
    if (dev == NULL) {
        fprintf(stderr, "Couldn't find default device: %s\n",
            errbuf);
        exit(EXIT_FAILURE);
    }
  }

  /* get network number and mask associated with capture device */
  if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
        fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
        dev, errbuf);
    net = 0;
    mask = 0;
  }

  /* print capture info */
  printf("Device: %s\n", dev);
  printf("Number of packets: %d\n", num_packets);
  printf("Filter expression: %s\n", filter_exp);


  /* open capture device */
  //handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
  handle = pcap_create(dev, errbuf);
  if (handle == NULL) {
    fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
    exit(EXIT_FAILURE);
  }

  pcap_set_snaplen(handle, 1518);
  pcap_set_promisc(handle, 1);
  pcap_set_timeout(handle, 1000);
  pcap_set_buffer_size(handle, 20971520);
  pcap_activate(handle);


  /* make sure we're capturing on an Ethernet device [2] */
  if (pcap_datalink(handle) != DLT_EN10MB) {
    fprintf(stderr, "%s is not an Ethernet\n", dev);
    exit(EXIT_FAILURE);
  } 

  /* now we can set our callback function */
  pcap_loop(handle, 0/*num_packets*/, got_packet, NULL);

  /* cleanup */
  pcap_close(handle);

  printf("\nCapture complete.\n");

  return 0;
}

下面是pcap_loop()调用的数据包处理程序代码:

代码语言:javascript
复制
/*
* dissect packet
*/
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{

  static int count = 1;                   /* packet counter */

  /* declare pointers to packet headers */
  const struct sniff_ethernet *ethernet;  /* The ethernet header [1] */
  const struct sniff_ip *ip;              /* The IP header */
  const struct sniff_tcp *tcp;            /* The TCP header */
  const char *payload;                    /* Packet payload */

  int size_ip;
  int size_tcp;
  int size_payload;

  //printf("\nPacket number %d:\n", count);
  count++;
  //if(count >= 2852200)
  printf("count: %d\n", count);
  /* define ethernet header */
  ethernet = (struct sniff_ethernet*)(packet);

  /* define/compute ip header offset */
  ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
  size_ip = IP_HL(ip)*4;
  if (size_ip < 20) {
    //printf("   * Invalid IP header length: %u bytes\n", size_ip);
    return;
  }

  /* define/compute tcp header offset */
  tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
  size_tcp = TH_OFF(tcp)*4;

  /* compute tcp payload (segment) size */
  size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);

  return;
}

谢谢你的帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-20 08:54:53

CPU的使用情况如何?它是单一核心的15%还是所有核心的15%?如果它占所有核心的15%,而你有8个核心,它实际上是一个单一核心的100%以上。因此,这可以解释为什么您的单线程应用程序无法捕获所有数据包。

如果您无法使用pcap接收所有数据包,那么除了尝试使用另一个数据包接收机制之外,没有其他方法了。Linux有PF_PACKET套接字,这可能对您的情况有所帮助。根据这个答案:包? ...libpcap应该比PF_PACKET更好,因为libpcap更易于移植,并且在内部使用PF_PACKET的内存映射机制,这是很难使用的。

根据答案,libpcap使用了PF_PACKET的内存映射机制。您可以尝试在非内存映射模式下手动使用PF_PACKET,这样您的数据包访问机制就会有所不同。如果内存映射模式中存在错误,则可能导致数据包丢失。

你试过用tcpdump记录数据包捕获吗?Tcpdump在内部使用libpcap,所以如果tcpdump能够捕获所有数据包,而您的软件无法捕获,那么它就可以证明bug在您的软件中,而不是libpcap中的固有限制。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29159097

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档