忘记密码   免费注册 查看新帖 | 论坛精华区

ChinaUnix.net

  平台 论坛 博客 认证专区 大话IT 视频 徽章 文库 沙龙 自测 下载 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
最近访问板块 发新帖
查看: 502 | 回复: 6

[网络子系统] netif_receive_skb()没看明白,请教一下 [复制链接]

论坛徽章:
0
发表于 2017-03-07 14:55 |显示全部楼层

  1. int netif_receive_skb(struct sk_buff *skb)
  2. {
  3.         struct packet_type *ptype, *pt_prev;
  4.         struct net_device *orig_dev;
  5.         struct net_device *null_or_orig;
  6.         int ret = NET_RX_DROP;
  7.         __be16 type;

  8.         if (!skb->tstamp.tv64)
  9.                 net_timestamp(skb);

  10.         if (skb->vlan_tci && vlan_hwaccel_do_receive(skb))
  11.                 return NET_RX_SUCCESS;

  12.         /* if we've gotten here through NAPI, check netpoll */
  13.         if (netpoll_receive_skb(skb))
  14.                 return NET_RX_DROP;

  15.         if (!skb->iif)
  16.                 skb->iif = skb->dev->ifindex;

  17.         null_or_orig = NULL;
  18.         orig_dev = skb->dev;
  19.         if (orig_dev->master) {
  20.                 if (skb_bond_should_drop(skb))
  21.                         null_or_orig = orig_dev; /* deliver only exact match */
  22.                 else
  23.                         skb->dev = orig_dev->master;
  24.         }

  25.         __get_cpu_var(netdev_rx_stat).total++;

  26.         skb_reset_network_header(skb);
  27.         skb_reset_transport_header(skb);
  28.         skb->mac_len = skb->network_header - skb->mac_header;

  29.         pt_prev = NULL;

  30.         rcu_read_lock();

  31. #ifdef CONFIG_NET_CLS_ACT
  32.         if (skb->tc_verd & TC_NCLS) {
  33.                 skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
  34.                 goto ncls;
  35.         }
  36. #endif

  37.         list_for_each_entry_rcu(ptype, &ptype_all, list) {
  38.                 if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
  39.                     ptype->dev == orig_dev) {
  40.                         if (pt_prev)                     <font color="#ff0000">//问题1在这???????????????????????????,总觉得少执行了一次,应该为if(ptype)  ret=deliver_skb(skb,ptype,orig_dev);</font>
  41.                                 ret = deliver_skb(skb, pt_prev, orig_dev);
  42.                         pt_prev = ptype;
  43.                 }
  44.         }

  45. #ifdef CONFIG_NET_CLS_ACT
  46.         skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
  47.         if (!skb)
  48.                 goto out;
  49. ncls:
  50. #endif

  51.         skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
  52.         if (!skb)
  53.                 goto out;
  54.         skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
  55.         if (!skb)
  56.                 goto out;

  57.         type = skb->protocol;
  58.         list_for_each_entry_rcu(ptype,
  59.                         &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
  60.                 if (ptype->type == type &&
  61.                     (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
  62.                      ptype->dev == orig_dev)) {
  63.                         if (pt_prev)
  64.                                 ret = deliver_skb(skb, pt_prev, orig_dev);
  65.                         pt_prev = ptype;
  66.                 }
  67.         }

  68.         if (pt_prev) {
  69.                 ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
  70.         } else {
  71.                 kfree_skb(skb);
  72.                 /* Jamal, now you will not able to escape explaining
  73.                  * me how you were going to use this. :-)
  74.                  */
  75.                 ret = NET_RX_DROP;
  76.         }

  77. out:
  78.         rcu_read_unlock();
  79.         return ret;
  80. }
复制代码


没看明白pt_prev用来做什么,总觉得最后一个ptype没收数据包?

打赏鼓励一下!

论坛徽章:
15
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:51程序设计版块每日发帖之星
日期:2016-06-03 06:20:00程序设计版块每日发帖之星
日期:2016-06-02 06:20:00程序设计版块每日发帖之星
日期:2016-05-30 06:20:00程序设计版块每日发帖之星
日期:2016-03-19 06:20:00程序设计版块每日发帖之星
日期:2016-03-12 06:20:00程序设计版块每日发帖之星
日期:2016-03-11 06:20:00
发表于 2017-03-07 16:24 |显示全部楼层
那些handle_XXX的代码如果想让包处理流程结束的话,都得显式的处理pt_prev。

把代码写成这样就是为了在normal case下避免无谓的skb copy/clone,或者说节省一次skb_free。

1人打赏

论坛徽章:
0
发表于 2017-03-07 16:59 |显示全部楼层
还是没弄明白。。。。
  1.         list_for_each_entry_rcu(ptype, &ptype_all, list) {
  2.                 if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
  3.                     ptype->dev == orig_dev) {
  4.                         if (pt_prev)  
  5.                                 ret = deliver_skb(skb, pt_prev, orig_dev);
  6.                         pt_prev = ptype;
  7.                 }
  8.         }
复制代码


假设ptype_all中最后的一个元素为ptype_end,总觉得在循环结束后也没执行
                        if (ptype_end)  
                                ret = deliver_skb(skb, ptype_end, orig_dev);
而只对ptype_end 的前一个元素调用了deliver_skb(skb, pt_prev, orig_dev);
这样ptype_end对应的协议族不就没收到数据包了吗?

论坛徽章:
0
发表于 2017-03-09 10:33 |显示全部楼层
回复 3# ymc4444

看内核代码一定要联系上下文环境,二楼已经说的很清楚了,静下心来捋一捋代码,不要着急,你就会发现:
后续那些handle_ing(skb, &pt_prev, &ret, orig_dev),handle_bridge(skb, &pt_prev, &ret, orig_dev)和handle_macvlan(skb, &pt_prev, &ret, orig_dev)接口都都把pt_prev作为两级指针传进去了,然后你再进到每个handle_XXX()里面去,看看它们是在干什么就全都明白了。你真当kernel大牛们是在随便设计内核API和它们的参数的么?

最后,二楼的后半句“把代码写成这样就是为了在normal case下避免无谓的skb copy/clone,或者说节省一次skb_free。”你自己再去体会体会。。。

论坛徽章:
0
发表于 2017-03-28 22:41 |显示全部楼层
http://bbs.chinaunix.net/thread-1933943-1-1.html 可以参考这个, 个人觉得pt_prev语义上还是针对prev(vious), 有点"匹配上一个"的意思 (注意add 一个entry到ptype_all是"add to head"), 更认同这个帖子三楼@卖萌犯法的回答

论坛徽章:
15
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:51程序设计版块每日发帖之星
日期:2016-06-03 06:20:00程序设计版块每日发帖之星
日期:2016-06-02 06:20:00程序设计版块每日发帖之星
日期:2016-05-30 06:20:00程序设计版块每日发帖之星
日期:2016-03-19 06:20:00程序设计版块每日发帖之星
日期:2016-03-12 06:20:00程序设计版块每日发帖之星
日期:2016-03-11 06:20:00
发表于 2017-04-06 17:00 |显示全部楼层
自定义的ptype函数跟强制插入/内联的函数(handle_xxx)有本质的不同,
前者得到数据包的copy,不影响原始报文的流程(最后一个ptype[type]是终结点);
后者可以终止整个data path(跳过所有的ptype[type],但要保证所有的ptype[ALL]被调用——比如tcpdump依赖的af_packet)。

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-11-17 06:20:00
发表于 2017-04-17 16:29 |显示全部楼层
回复 1# ymc4444


之所以这样写的原因是:

1、协议处理程序会在处理完毕后调用kfree_skb()函数准备释放该skb,因此会导致skb->users减1

2、因为可能存在多个协议处理程序,所以前一个ptype会在处理完毕进行kfree_skb,于是就需要借助deliver_skb来增加一下skb->users的计数,否则后面的ptype就没有机会了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

【有奖调查】AI时代如何迎接未知挑战?

人工智能一直在医疗行业扮演着重要角色,最早的专家系统和后来的基因诊断都是人工智能技术在医疗的行业探索。近年来,随着深度学习等技术的进步,人工智能在医疗行业的应用领域不断扩展,医学影像智能诊断、语音电子病历、癌症智能诊断等均已逐渐成为热门发展方向。
而作为人工智能重要推动力的深度学习技术的快速发展却亟需认知系统的强力支撑。
----------------------------------------
活动时间:2017年5月15日-6月5日

调查入口>>
  

北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:1101082001
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP