• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Linux GSO逻辑分析

Linux GSO逻辑分析

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了影驰9600gso显卡,9600gso512显卡驱动,影驰 9600gso加强版,gso,9600gso等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Linux GSO逻辑分析


Linux GSO逻辑分析

——lvyilong316(转载请注明出处)
(注:对应linux kernel 代码为linux 2.6.32)

GSO用来扩展之前的TSO,目前已经并入upstream内核。TSO只能支持tcp协议,而GSO可以支持tcpv4,tcpv6, udp等协议。在GSO之前,skb_shinfo(skb)有两个成员ufo_size, tso_size,分别表示udpfragmentation offloading支持的分片长度,以及tcp segmentation offloading支持的分段长度,现在都用skb_shinfo(skb)->gso_size代替。

skb_shinfo(skb)->ufo_segs,skb_shinfo(skb)->tso_segs也被替换成了skb_shinfo(skb)->gso_segs,表示分片的个数。

gso用来delay 大包的分片,所以一直到dev_hard_start_xmit函数才会调用到。

l dev_hard_start_xmit


  1. int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
  2. struct netdev_queue *txq)
  3. {
  4. const struct net_device_ops *ops = dev->netdev_ops;
  5. int rc;

  6. if (likely(!skb->next)) {
  7. if (!list_empty(&ptype_all))
  8. dev_queue_xmit_nit(skb, dev);
  9. //判断网卡是否需要协议栈负责gso
  10. if (netif_needs_gso(dev, skb)) {
  11. //真正负责GSO操作的函数
  12. if (unlikely(dev_gso_segment(skb)))
  13. goto out_kfree_skb;
  14. if (skb->next)
  15. goto gso;
  16. }
  17. //……
  18. gso:
  19. do {
  20. //指向GSO分片后的一个skb
  21. struct sk_buff *nskb = skb->next;
  22. skb->next = nskb->next;
  23. nskb->next = NULL;
  24. if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
  25. skb_dst_drop(nskb);
  26. //将通过GSO分片后的包逐个发出
  27. rc = ops->ndo_start_xmit(nskb, dev);
  28. if (unlikely(rc != NETDEV_TX_OK)) {
  29. nskb->next = skb->next;
  30. skb->next = nskb;
  31. return rc;
  32. }
  33. txq_trans_update(txq);
  34. if (unlikely(netif_tx_queue_stopped(txq) && skb->next))
  35. return NETDEV_TX_BUSY;
  36. } while (skb->next);

  37. skb->destructor = DEV_GSO_CB(skb)->destructor;

  38. out_kfree_skb:
  39. kfree_skb(skb);
  40. return NETDEV_TX_OK;
  41. }


那是不是所有skb在发送时都要经过GSO的逻辑呢?显然不是,只有通过netif_needs_gso判断才会进入GSO的逻辑,下面我们看下netif_needs_gso是如何判断的。


  1. static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
  2. {
  3. return skb_is_gso(skb) &&
  4. (!skb_gso_ok(skb, dev->features) ||
  5. unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
  6. }


注意这里最后用了一个unlikely,因为如果通过前面的判断,说明网卡是支持GSO的,而一般网卡支持GSO也就会支持CHECKSUM_PARTIAL。进入GSO处理的第一个前提是skb_is_gso函数返回真,看下skb_is_gso的逻辑:


  1. static inline int skb_is_gso(const struct sk_buff *skb)
  2. {
  3. return skb_shinfo(skb)->gso_size;
  4. }


skb_is_gso的逻辑很简单,返回skb_shinfo(skb)->gso_size,所以进入GSO处理逻辑的必要条件之一是skb_shinfo(skb)->gso_size不为0,那么这个字段的含义是什么呢?gso_size表示生产GSO大包时的数据包长度,一般时mss的整数倍。下面看skb_gso_ok,如果这个函数返回False,就可以进入GSO处理逻辑。


  1. static inline int skb_gso_ok(struct sk_buff *skb, int features)
  2. {
  3. return net_gso_ok(features, skb_shinfo(skb)->gso_type) &&
  4. (!skb_has_frags(skb) || (features & NETIF_F_FRAGLIST));
  5. }


skb_shinfo(skb)->gso_type包括SKB_GSO_TCPv4, SKB_GSO_UDPv4,同时NETIF_F_XXX的标志也增加了相应的bit,标识设备是否支持TSO, GSO, e.g.

  1. NETIF_F_TSO = SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT
  2. NETIF_F_UFO = SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT
  3. #define NETIF_F_GSO_SHIFT 16


通过以上三个函数分析,以下三个情况需要协议栈负责GSO。


下面看GSO的协议栈处理逻辑,入口就是dev_gso_segment。

l dev_gso_segment

协议栈的GSO逻辑是在dev_gso_segment中进行的。这个函数主要完成对skb的分片,并将分片存放在原始skb的skb->next中,这也是GSO的主要工作。


  1. static int dev_gso_segment(struct sk_buff *skb)
  2. {
  3. struct net_device *dev = skb->dev;
  4. struct sk_buff *segs;
  5. int features = dev->features & ~(illegal_highdma(dev, skb) ?
  6. NETIF_F_SG : 0);

  7. segs = skb_gso_segment(skb, features);

  8. /* Verifying header integrity only. */
  9. if (!segs)
  10. return 0;

  11. if (IS_ERR(segs))
  12. return PTR_ERR(segs);

  13. skb->next = segs;
  14. DEV_GSO_CB(skb)->destructor = skb->destructor;
  15. skb->destructor = dev_gso_skb_destructor;

  16. return 0;
  17. }


主要分片逻辑由skb_gso_segment来处理,这里我们主要看下析构过程,此时skb经过分片之后已经是一个skb list,通过skb->next串在一起,此时把初始的skb->destructor函数存到skb->cb中,然后把skb->destructor变更为dev_gso_skb_destructor。dev_gso_skb_destructor会把skb->next一个个通过kfree_skb释放掉,最后调用DEV_GSO_CB(skb)->destructor,即skb初始的析构函数做最后的清理。

l skb_gso_segment

这个函数将skb分片,并返回一个skb list。如果skb不需要分片则返回NULL。


  1. struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
  2. {
  3. struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
  4. struct packet_type *ptype;
  5. __be16 type = skb->protocol;
  6. int err;

  7. skb_reset_mac_header(skb);
  8. skb->mac_len = skb->network_header - skb->mac_header;
  9. __skb_pull(skb, skb->mac_len);
  10. //如果skb->ip_summed 不是 CHECKSUM_PARTIAL,那么报个warning,因为GSO类型的skb其ip_summed一般都是CHECKSUM_PARTIAL
  11. if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
  12. struct net_device *dev = skb->dev;
  13. struct ethtool_drvinfo info = {};
  14. WARN(……);
  15. if (skb_header_cloned(skb) &&
  16. (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
  17. return ERR_PTR(err);
  18. }
  19. rcu_read_lock();
  20. list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
  21. if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
  22. if (unlikely(skb->ip_summed != CHECKSUM_P
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Linux GSO逻辑分析
  • linux tcp GSO和TSO实现

相关文章

  • 2017-05-26利用zabbix监控国际线路的延迟情况
  • 2017-05-26安卓开源项目周报0411,安卓开源项目0411
  • 2017-05-26组件RecyclerView的应用(一),组件recyclerview
  • 2017-05-26andorid build tools 19.1,andorid19.1
  • 2017-05-26Android开发学习之路--传感器之初体验
  • 2017-05-26Keepalived实现高可用
  • 2017-05-26android 所有焦点问题--Focus,android--focus
  • 2017-05-26VS2015墙内创建ionic2,vs2015墙ionic2
  • 2017-05-26Android程序中--不能改变的事情,android程序--改变
  • 2017-05-26android发送邮件

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 年底了,给MySQL做个例行巡检吧
    • Android开发:控件之WebView
    • Android系统的“程序异常退出”,android退出
    • 功能强大的StickyHeaderListView:标题渐变、吸附悬停、筛选分类、动态头部,
    • Linux内核系列—操作系统开发之HelloWorld,linuxhelloworld
    • SharedPreferences详解,sharedpreferences
    • LVS 内核实现分析(1)
    • Android View体系(二)实现View滑动的六种方法
    • 关于Pacemaker集群配置的版本
    • Android Studio中找出不再使用的资源,androidstudio

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有