免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4278 | 回复: 12
打印 上一主题 下一主题

[网络子系统] 网络内核的接收软中断处理能被内核定时器处理程序中断吗【已解决】 [复制链接]

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-01-08 11:30 |只看该作者 |倒序浏览
本帖最后由 jiufei19 于 2013-01-09 11:35 编辑

最近一直在阅读Linux的网络内核部分代码,目前正在阅读TCP部分的处理,忽然产生了一个以前一直没有注意到的问题,即正常的协议栈处理比如net_rx_action这个接收软中断,能被内核中定义的定时器程序中断吗?

我举个例子,例如TCP正在处理收到的一个分段,发现此分段是一个ACK,于是更新tp->snd_una,此时在即将回收所有在此tp->snd_una序号之前的重传分段前,发生了RTO超时,那么,RTO的超时处理程序能否立刻中断对ACK的处理?即此时被重传的数据其实已经被刚才那个ACK所确认了,只是因为稍微晚了点点,现在RTO已经到时了,那么会怎样处理呢?

请大家解惑,谢谢!

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
2 [报告]
发表于 2013-01-08 12:05 |只看该作者
仔细阅读了下Linux kernel development一书,其中有如下一段话:

Next, the run_local_timers()  function marks a softirq (see Chapter 8,“Bottom  Halves and Deferring Work”) to handle the execution of any expired timers.

很明显,linux内核将定时器处理程序作为了软中断,因此定时器处理程序似乎不可能去中断正在运行的其他软中断,比如net_rx_action。我们来看看源码

  897 void run_local_timers(void)
   898 {
   899     raise_softirq(TIMER_SOFTIRQ);
   900     softlockup_tick();
   901 }  
这段代码开始准备启动和定时器相关软中断,接着我们来看raise_softirq
  337 void fastcall raise_softirq(unsigned int nr)
  338 {
  339     unsigned long flags;
  340
  341     local_irq_save(flags);
  342     raise_softirq_irqoff(nr);
  343     local_irq_restore(flags);
  344 }

我们再来看raise_softirq_irqoff

  318 inline fastcall void raise_softirq_irqoff(unsigned int nr)
  319 {
  320     __raise_softirq_irqoff(nr);
  321
  322     /*
  323      * If we're in an interrupt or softirq, we're done
  324      * (this also catches softirq-disabled code). We will
  325      * actually run the softirq once we return from
  326      * the irq or softirq.
  327      *
  328      * Otherwise we wake up ksoftirqd to make sure we
  329      * schedule the softirq soon.
  330      */
  331     if (!in_interrupt())
  332         wakeup_softirqd();
  333 }

很明显上面的代码注释说明了只有在执行完irq或softirq后,才能执行定时器处理程序,因此感觉RTO超时处理程序不能中断tcp_ack的处理。


不知道我的分析是否正确,请各位指正

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
3 [报告]
发表于 2013-01-08 12:23 |只看该作者
本帖最后由 瀚海书香 于 2013-01-10 14:32 编辑

回复 1# jiufei19
我举个例子,例如TCP正在处理收到的一个分段,发现此分段是一个ACK,于是更新tp->snd_una,此时在即将回收所有在此tp->snd_una序号之前的重传分段前,发生了RTO超时,那么,RTO的超时处理程序能否立刻中断对ACK的处理?即此时被重传的数据其实已经被刚才那个ACK所确认了,只是因为稍微晚了点点,现在RTO已经到时了,那么会怎样处理呢?


1. 软中断不会被软中断所打断。
2. 协议栈的处理有可能是在进程上下文中运行(比如用户态系统调用),有可能被软中断打断
3. 内核在处理一个可能被软中断处理的代码的时候,通过禁止软中断来实现。

所以你的描述的问题应该是:tcp在处理ingress的数据包流程



tcp_v4_rcv()
{
   if(sock被用户进程锁定)
          将skb放到sk_backlog,然后返回,等待release_sock的时候处理sk_backlog中的数据包
   else(tcp_prequeue){
          if(开启了tcp_low_lattency||tcp_prequeue队列满)
                直接调用sk_backlog_rcv,tcp_v4_do_rcv,运行在软中断的环境中,不会被软中断打断。
          else
                放到prequeue队列,然后返回,等待tcp_prequeue_process处理
   }
}

tcp_recvmsg的处理:
         tcp_prequeue_process()--->sk_backlog_rcv-->backlog_rcv--->tcp_v4_do_rcv


tcp_prequeue_process函数代码可以看到,里面添加了禁止软中断的代码。
  1. static void tcp_prequeue_process(struct sock *sk)
  2. {
  3.         struct sk_buff *skb;
  4.         struct tcp_sock *tp = tcp_sk(sk);

  5.         NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPPREQUEUED);

  6.         /* RX process wants to run with disabled BHs, though it is not
  7.          * necessary */
  8.         local_bh_disable();
  9.         while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
  10.                 sk_backlog_rcv(sk, skb);
  11.         local_bh_enable();

  12.         /* Clear memory counter. */
  13.         tp->ucopy.memory = 0;
  14. }
复制代码
综合上述可见,tcp在处理接收队列数据包的时候,是不会被软中断打断的。
   

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
4 [报告]
发表于 2013-01-08 12:25 |只看该作者
回复 2# jiufei19
很明显上面的代码注释说明了只有在执行完irq或softirq后,才能执行定时器处理程序,因此感觉RTO超时处理程序不能中断tcp_ack的处理。


不知道我的分析是否正确,请各位指正

你这个分析只是上面回复的第一个情况,还需要继续深入进去啊。。。

   

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
5 [报告]
发表于 2013-01-08 12:40 |只看该作者
本帖最后由 jiufei19 于 2013-01-08 12:46 编辑

感谢斑竹的指正,那么再请斑竹回到我之前那个问题,即http://bbs.chinaunix.net/thread-4061918-1-1.html帖子中描述的那个问题,即怎么会发生对方确认了old data,而这些old data却并没有从重传队列中删除,以至于发送方将old data和FIN合并在一起了的现象?这究竟是什么场景才能发生的呢?

论坛徽章:
0
6 [报告]
发表于 2013-01-08 15:23 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
7 [报告]
发表于 2013-01-08 16:16 |只看该作者
感谢答复。请看我下面的说明

我从头跟踪了下代码的执行,是从链路层的处理如process_backlog这个函数开始,直到tcp_v4_do_rcv,然后进入到tcp_rcv_established,然后再进入tcp_ack,的确没有发现有对local_bh_disable的调用,那么是否可以说RTO的超时处理程序(还是一个softirq)就可以打断tcp_ack的执行了? 但是如果可以打断tcp_ack的话,那么raise_softirq_irqoff中的那段注释又讲不通了,彻底晕了!

论坛徽章:
0
8 [报告]
发表于 2013-01-08 22:20 |只看该作者
jiufei19 发表于 2013-01-08 16:16
感谢答复。请看我下面的说明

我从头跟踪了下代码的执行,是从链路层的处理如process_backlog这个函数开始 ...


假设在运行tcp_ack的时候,RTO timeout了,得分两种情况
1. timer softirq deliver到本地cpu
看一下__do_softirq(), 所有的软中断都是在local_bh_disable()的环境下运行的,所以tcp_ack在运行的时候,如果local cpu来了一个时钟中断,它只会在run_local_timers()里raise timer softirq,不会打断已经在运行的net rx softirq去先运行timer softirq, 处理完时钟中断后,softirq会继续tcp_ack的运行,然后才会处理新的timer softirq.

2. timer softirq deliver到另外的cpu
如果时钟中断被deliver到了另外的cpu的话,就需要靠sock->sk_lock来同步了,见tcp_write_timer()里的bh_lock_sock(),和tcp_v4_rcv()里的bh_lock_sock_nested()。

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
9 [报告]
发表于 2013-01-08 22:44 |只看该作者
eexplorer,好久不见,太感谢了。

救人救到底,请帮我看看因我的另外一个帖子引起的此问题,请看该帖 http://bbs.chinaunix.net/thread-4061918-1-1.html

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
10 [报告]
发表于 2013-01-08 23:01 |只看该作者
的确,从逻辑上讲,当前cpu上的RTO超时处理程序肯定不会打断正在执行的协议栈处理如tcp_ack函数,否则整个协议栈处理就会被各类定时器程序弄得支离破碎。

我之前忽略了__do_softirq()中执行local_bh_disable(),以为在协议处理程序中有。因为有的协议处理程序中的确有对local_bh_disable()的调用。

再次感谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP