惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
Help Net Security
Help Net Security
P
Proofpoint News Feed
J
Java Code Geeks
爱范儿
爱范儿
Last Week in AI
Last Week in AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
F
Full Disclosure
Google DeepMind News
Google DeepMind News
H
Help Net Security
G
Google Developers Blog
Jina AI
Jina AI
Vercel News
Vercel News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
Lohrmann on Cybersecurity
S
Schneier on Security
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
Security Archives - TechRepublic
Security Archives - TechRepublic
阮一峰的网络日志
阮一峰的网络日志
N
News and Events Feed by Topic
GbyAI
GbyAI
B
Blog
O
OpenAI News
博客园_首页
Cisco Talos Blog
Cisco Talos Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Hacker News: Ask HN
Hacker News: Ask HN
TaoSecurity Blog
TaoSecurity Blog
腾讯CDC
MongoDB | Blog
MongoDB | Blog
M
MIT News - Artificial intelligence
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
Webroot Blog
Webroot Blog
Simon Willison's Weblog
Simon Willison's Weblog
Y
Y Combinator Blog
C
Cisco Blogs
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
The Exploit Database - CXSecurity.com
Security Latest
Security Latest
AI
AI
W
WeLiveSecurity
aimingoo的专栏
aimingoo的专栏
The Register - Security
The Register - Security
Project Zero
Project Zero
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
Netflix TechBlog - Medium
Blog — PlanetScale
Blog — PlanetScale

博客园 - YZG

zigbee路由(报文实例) Zigbee系列(路由机制) Zigbee系列(end device) Zigbee系列(网络) Zigbee系列(概览) kallsyms , addr to symbol Linux checksum flag in kernel ubuntu apt-xxx 清空DNS缓存 shell loop shell 参数 power sequece grep 文件内容搜索 virtual machine AVR地址空间 altera 与 xilinx fifo 时序的区别 如何在Linux下实现50万并发 Linux tcp socket相关参数设置 对Linux下socket限制的理解
netif_receive_skb pt_prev why?
YZG · 2012-09-21 · via 博客园 - YZG

关于netif_receive_skb中的一个链表处理问题

正文

在netif_receive_skb中有一段代码是将receive的数据包clone一份交给ptype_all的链,代码如下:
……
pt_prev=NULL;
list_for_each_entry_rcu(ptype,&ptype_all,list){
      if(!ptype->dev||ptype->dev==skb->dev){
           if(pt_prev)
                 ret=deliver_skb(skb,pt_prev,orig_dev);
           pt_prev=ptype;
      }
}

我感觉上述代码有点迷糊啊,既然是遍历ptype_all链,为什么需要一个pt_prev保存一下呢,直接下面这样不就就行了
list_for_each_entry_rcu(ptype,&ptype_all,list){
      if(!ptype->dev||ptype->dev==skb->dev){
                 ret=deliver_skb(skb,ptype,orig_dev);
      }
}
那位大虾给讲解一下

[ 本帖最后由 Godbach 于 2009-8-21 16:06 编辑 ]


作者: Godbach    时间: 2009-8-21 16:07

LZ好啊,我把你的标题编辑了一下。希望有更多人讨论你的问题


作者: dreamice    时间: 2009-8-21 16:15

QUOTE:

原帖由 瀚海书香 于 2009-8-21 15:59 发表
在netif_receive_skb中有一段代码是将receive的数据包clone一份交给ptype_all的链,代码如下:
……
pt_prev=NULL;
list_for_each_entry_rcu(ptype,&ptype_all,list){
      if(!ptype->dev||ptype->dev==sk ...


这里是为了确定pt_prev是不是已经被投递了,如果已经被投递了,就往下遍历。
这个可能是为了避免smp并发处理造成对包的多次deliver。


作者: 瀚海书香    时间: 2009-8-21 16:16     标题: 回复 #2 Godbach 的帖子

谢谢版主

麻烦版主给分析一下吧


作者: Godbach    时间: 2009-8-21 16:21

看一下dreamice兄的解释。

但从程序上来看,基本上是遍历到当前节点时,将保存的前一个非空节点deliver。


作者: 瀚海书香    时间: 2009-8-21 16:25     标题: 回复 #3 dreamice 的帖子

可否详细讲解一下
上面那种情况是如何防止smp的多次deliver,以及下面这种情况又是在怎样的情况下产生多次deliver的??
小弟愿闻其详


作者: Godbach    时间: 2009-8-21 16:31

按理说遍历链表的时候已经加锁了啊


作者: 瀚海书香    时间: 2009-8-21 16:37

而且更让我疑惑的是,按上面的那种情况,好像链表最后符合条件的那个ptype没有deliver啊


作者: dreamice    时间: 2009-8-21 17:26

QUOTE:

原帖由 瀚海书香 于 2009-8-21 16:25 发表
可否详细讲解一下
上面那种情况是如何防止smp的多次deliver,以及下面这种情况又是在怎样的情况下产生多次deliver的??
小弟愿闻其详


我先看看代码


作者: platinum    时间: 2009-8-21 17:43

因为后面还要用


作者: 瀚海书香    时间: 2009-8-21 19:13     标题: 回复 #10 platinum 的帖子

之后的代码就是bridge和vlan,然后就是ptype_base对应的协议处理函数。
在ptype_base的链表遍历中的确会deliver给ptype_all中的最后一个,但是为什么要到这里才deilver给ptype_all中的最后一个呢?
还有如果说在bridge或者vlan的处理中就返回了,就走不到这一步,那样ptype_all的最后一个就不能收到数据包了


作者: ShadowStar    时间: 2009-8-22 01:34

QUOTE:

原帖由 瀚海书香 于 2009-8-21 19:13 发表
之后的代码就是bridge和vlan,然后就是ptype_base对应的协议处理函数。
在ptype_base的链表遍历中的确会deliver给ptype_all中的最后一个,但是为什么要到这里才deilver给ptype_all中的最后一个呢?
还有如果说 ...

逻辑处理上没有问题。

pt_prev意思就是“前一个packet_type”。

可以这么说,最后一个ptype_all的func是在ptype_base的循环中调用的。(如果ptype_base的循环中if成立)

你看在ptype_base循环下面,还有个if(pt_prev) {......

我也不清楚为什么这么做

而且,我觉得这里有点问题。
因为deliver_skb(就是执行packet_type->func())是有可能kfree_skb()的。
这样的话,后面如果还有匹配到的话,skb已经被释放了。

[ 本帖最后由 ShadowStar 于 2009-8-22 01:46 编辑 ]


作者: 瀚海书香    时间: 2009-8-22 09:08     标题: 回复 #12 ShadowStar 的帖子

逻辑处理上没有问题。

pt_prev意思就是“前一个packet_type”。

可以这么说,最后一个ptype_all的func是在ptype_base的循环中调用的。(如果ptype_base的循环中if成立)

你看在ptype_base循环下面  


的确是这样的,但是如果说没有运行到这就return了呢?

QUOTE:

而且,我觉得这里有点问题。
因为deliver_skb(就是执行packet_type->func())是有可能kfree_skb()的。


这个地方是没问题的,因为deliver_skb的时候有操作atomic_inc(&skb->users);而之后的 kfree_skb()也是atomic_dec(&skb->users),只有当skb->users=0的时候才真正的 free(skb)和free(skb->data)


作者: eexplorer    时间: 2009-8-22 11:33     标题: 回复 #1 瀚海书香 的帖子

这个还是涉及到优化的问题。

如 果只有一个packet_type match的话,我们就可以直接call pt_prev->func(skb, skb->dev, pt_prev, orig_dev),注意这里的话并没有increase skb->uesrs,这个skb就是这个handler所独有的。

如 果存在多个handler match的话,在deliver_skb的时候需要increase skb->users,然后在这个handler里,如果这个skb是共享的,就需要skb_clone这个skb (see skb_share_check for details)

所以这么麻烦,就是为了优化最common的一个case,就是只有一个handler match的话,省去了skb_clone的开销。

[ 本帖最后由 eexplorer 于 2009-8-22 11:35 编辑 ]


作者: 瀚海书香    时间: 2009-8-22 11:53     标题: 回复 #14 eexplorer 的帖子

的确是这样的。
但 是在ptype_all类型的handle之后紧跟着是bridge和vlan的处理,之后是ptype_base类型handle的处理,但是如果 bridge和vlan两个处理的某一个返回值为NULL,则直接跳转到out:处执行,这样的话最后一个handle就不能收到数据包了?


作者: eexplorer    时间: 2009-8-22 13:14

QUOTE:

原帖由 瀚海书香 于 2009-8-22 11:53 发表
的确是这样的。
但是在ptype_all类型的handle之后紧跟着是bridge和vlan的处理,之后是ptype_base类型handle的处理,但是如果bridge和vlan两个处理的某一个返回值为NULL,则直接跳转到out:处执行,这样的话最后一 ...


看了一下handle_bridge和hanel_macvlan,两个函数都有这样一段code:
        if (*pt_prev) {
                *ret = deliver_skb(skb, *pt_prev, orig_dev);
                *pt_prev = NULL;
        }


作者: 瀚海书香    时间: 2009-8-22 13:20     标题: 回复 #16 eexplorer 的帖子

那就明白了
多谢了