dev_queue_xmit 导致死机。

发布于 2022-10-15 06:02:55 字数 4590 浏览 24 评论 0

小弟最近在研究零拷贝发送。所以需要直接调用dev_queue_xmit 进行发送。 可是之前调用dev_queue_xmit 都能正常发送,今天突然出现死机。这里贴出代码,希望哪位大大能够帮忙看一下。

  1. data = kmap(fifo_item->page);
  2.   fifo_item->kernel_vir_addr = (unsigned long)data;
  3.   data += offset;
  4.   block_header = (struct UBM_block_header_t*)data;
  5.   size = block_header->end - block_header->head;
  6.   /* build skb head*/
  7.   skb_orig = kmem_cache_alloc(skbuff_head_cache, GFP_KERNEL & ~__GFP_DMA);
  8.   if (assemble_skb(skb_orig,size,data+block_header->head)<0){
  9.           res = -1;
  10.           kmem_cache_free(skbuff_head_cache, skb_orig);
  11.           goto out;
  12.   }
  13.   skb = skb_clone(skb_orig, GFP_ATOMIC & ~__GFP_DMA);
  14.   if (NULL == skb){
  15.           res = -1;
  16.           kmem_cache_free(skbuff_head_cache, skb_orig);
  17.           goto out;
  18.   }
  19.   /*init send infomation in UBM fifo item */
  20.   fifo_item->send_info.skb_orig = skb_orig;
  21.   fifo_item->send_info.sleeping_task = current;
  22.   fifo_item->send_info.status = status;
  23.   /*build skb body*/
  24.   skb->dev = dev;
  25.   skb->pkt_type = PACKET_OTHERHOST;//PACKET_OUTGOING;
  26.   skb->protocol = __constant_htons(ETH_P_IP);
  27.   skb->ip_summed = CHECKSUM_NONE;
  28.   skb->destructor = UBM_skb_destroy;
  29.   skb->priority = 0;
  30.   skb->next = NULL;
  31.   skb_reserve (skb,size);
  32.   skb_push(skb, block_header->tail - block_header->data);
  33.   skb_push (skb, block_header->data - block_header->transport_header);
  34.   skb_reset_transport_header(skb);
  35.   if (sockfd < 0){
  36.           skb_push (skb, block_header->transport_header - block_header->network_header);  
  37.           skb_reset_network_header(skb);
  38.           iph = ip_hdr(skb);
  39.           ip_send_check(iph);
  40.           skb_push(skb, block_header->network_header - block_header->mac_header);
  41.           skb_reset_mac_header(skb);
  42.           res = dev_queue_xmit(skb);
  43.           if (res != NETDEV_TX_OK)
  44.                   MSG_DEBUG("Failed to send");
  45.           else
  46.                   MSG_DEBUG("Send out");
  47.   }
  48.   else{
  49.           inet->inet_daddr = daddr;
  50.           ubm_sock->sk->sk_protocol = ULP_PROTOCOL_NUMBER;
  51.           skb->sk = ubm_sock->sk;
  52.           res = ip_queue_xmit(skb);
  53.           if (res != NETDEV_TX_OK)
  54.                   MSG_DEBUG("Failed to send, res : %d\n",res);
  55.           else{
  56.                   MSG_DEBUG("Send out %lu, res : %d\n", send_counter++,res);
  57.           }
  58.   }

复制代码blockhead 是一个用户空间结构。在发送页面当中。他的head,tail,data,end 是数据相对于数据头部的偏移量。在调试的时候,输出信息正确。CLONE SKB 的原因是我的数据区处于用户空间。为了防止内核释放掉SKB的数据区,所以克隆。然后当实际释放的时候,克隆的SKB会KUNMAP掉数据区,并且释放原SKB的头部。assemble_skb 负责组合SKB 头 与数据区,并且初始化skb_shared_info信息。 dev 是在网络设备启动时初始话的,在之前有检测是否为空。 奇怪的是,如果我通过提交SOCK信息,并且调用ip_queue_xmit,那么就一切正常。但是调用dev_queue_xmit就死机。另外就是,我通过实验发现当我调用ip_queue_xmit的时候,如果我发包速度非常快,那么前N个包会丢失,但返回信息是正常的。有哪位大大知道这是怎么回事。谢谢了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

冷弦 2022-10-22 06:02:55

我自己顶一下,希望有哪位大大能够帮忙看一下,提一些建议。

转角预定愛 2022-10-22 06:02:55

想问一下,这段代码是工作于哪个位置的?
注册在什么 hook 下,还是直接嵌在内核中什么位置?

落墨 2022-10-22 06:02:55

回复 3# platinum

没有注册在HOOK函数下,是自己签到模块里,由用户直接呼叫的。 另外问题已经解决了,原因是在用户端,我在极短的时间内发送同一个数据包。那么当DMA 这个数据包到网卡的同时,我另外一个CPU在对这个数据包的IP头进行CHECKSUM, 这样就造成死机了。

[浮城] 2022-10-22 06:02:55

回复  platinum

没有注册在HOOK函数下,是自己签到模块里,由用户直接呼叫的。 另外问题已经解决了,原 ...
bl851031 发表于 2011-05-29 21:03

哦,是不是 lock 没处理好,产生竞态导致的死机?

你げ笑在眉眼 2022-10-22 06:02:55

哦,是不是 lock 没处理好,产生竞态导致的死机?
platinum 发表于 2011-05-30 10:35

恩,差不多一个原理,但不完全是LOCK的原因。加锁只能保证内核区安全,但是用户仍有可能更改正在DMA的内存。我后来用MPROTECT来解决这个问题。然后加上信号处理函数。

你曾走过我的故事 2022-10-22 06:02:55

哦,是不是 lock 没处理好,产生竞态导致的死机?
platinum 发表于 2011-05-30 10:35

而且考虑到快速转发的原因,我接受的数据同时也是使用用户内存。这个时候由于接受过程发生在硬中断内,我是无法加锁的。如果我使用底半操作,那会影响响应时间。所以我最后还是设置了一个标志位,同时在即将驱动即将DMA前加上MPROTECT保护。在影中断处理完返还用户时,去除保护,并重写标志位。这样寄希望于用户按照接口来操作,检查标志位。同时即使出现非法操作,也能通过信号处理机制解决。

半﹌身腐败 2022-10-22 06:02:55

而且考虑到快速转发的原因,我接受的数据同时也是使用用户内存。这个时候由于接受过程发生在硬中断内, ...
bl851031 发表于 2011-05-30 20:50

    bl851031 兄研究的好深啊,佩服佩服!!!:)

零拷贝技术仅适用于那些需要在 userspace 处理数据包的情况?
如果所有程序都是直接在内核处理的,是不是就无所谓是不是零拷贝了?
不知道我对零拷贝的理解是否有问题,还请 bl851031 兄多多指点!

汐鸠 2022-10-22 06:02:55

回复 8# platinum

我也是个菜鸟,只是毕业设计是这个东东,不得不硬着头皮上。 关于你的问题,原则上是这样的。但是也要看你的模块在内核的哪一个层。比如如果你的模块是紧贴着VFS层,那么你就要考虑数据包分片(发送)或者线性化(接收)时可能发生的拷贝。不过我想这个可以通过你注册新的协议族来解决。另外零拷贝我体会还有两个好处。一个是内核内存实在是小了点,只有892MB,那么对于大量需要做LOG操作的数据包你就可能会丢包。当然你可以在内核中非配HIGH_MEM 但那样和用户就没区别了。其次是,驱动在每次接收到一个PACKET后,会重新非配一段内存等待接受第二轮的包。这个时间,如果用零拷贝可以提前到INIT态里面,即在INIT时就装配好SKB,然后当DRIVER需要的时候就直接提供,而避免了重新非配。

眼趣 2022-10-22 06:02:55

回复  platinum

其次是,驱动在每次接收到一个PACKET后,会重新非配一段内存等待接受第二轮的包。这个时间,如果用零拷贝可以提前到INIT态里面,即在INIT时就装配好SKB,然后当DRIVER需要的时候就直接提供,而避免了重新非配。bl851031 发表于 2011-06-01 21:10

因为没研究过驱动代码,不知道是不是利用 slab 或 slub 分配的,如果是,他本身效率也是很高的

我感觉这个意义还是很大的,无论处理数据是在 kernel space 还是 user space,这样都可以简化处理路径
目前针对这个有具体实现吗?可否与大家分享一下?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文