记录一下linux数据包从网卡进入协议栈的过程,不涉及驱动,不涉及其他层的协议处理。

内核是如何知道网卡收到数据的,这就涉及到网卡和内核的交互方式:

轮询(poll):内核周期性的检查网卡,查看是否收到数据。优点:数据包非常多的时候,这种处理方法会非常快速有效。缺点:数据包少的时候会CPU总是轮询却没有收到数据包,造成CPU资源的浪费。这种方法很少使用。

中断(interrupt):网卡收到数据就给内核发送硬件中断打断内核的正常运行,让内核来处理数据包。优点:在数据包少的时候CPU能及时中断其他任务来处理数据包,比较高效。缺点:数据包多的时候每个数据包都引发一次中断,造成CPU频繁地在收包过程和其他过程之间切换,浪费时间。在极端情况下收包中断可能会一直抢占CPU造成软中断无法运行,收包队列得不到处理,进而造成大量丢包。这就是所谓的receive-livelock。

Llinux早期是采用中断的方式处理数据包的,之后引入了另一种方式NAPI,NAPI结合了轮询和中断的优点,在数据包少的时候采用中断方式,数据包多的时候采用轮询的方式,从而在两种极端情况下也会有比较好的表现。

在NAPI下收包的过程

先看一个比较关键的结构softnet_data,每个逻辑CPU都有一个softnet_data结构,这个结构的poll_list是非常重要的。

struct softnet_data
{struct net_device       *output_queue;//收报队列,这个队列是给传统收报方法兼容新收报架构用的(backlog_dev),用来模拟NAPI的struct sk_buff_head     input_pkt_queue;//用于收包的net_devicestruct list_head        poll_list;struct sk_buff          *completion_queue;//backlog_dev是一个伪造的net_device用来来处理input_pkt_queue里的数据struct net_device       backlog_dev;    /* Sorry. 8) */
};

收包过程可以分成两步:

  1. 当网卡收到数据包中断发生,中断处理程序就会把当前网卡的net_device插入当前CPU的softnet_data的poll_list链表,调度软中断。
  2. 软中断处理链表poll_list,读出数据包,放入协议栈。

第一步的中断的代码可以参考drivers/net/tg3.c文件的tg3_interrupt函数,中断发生的时候它会调用netif_rx_schedule把当前网卡的net_device插入当前CPU的softnet_data的poll_list链表。netif_rx_schedule函数又调度了软中断NET_RX_SOFTIRQ。大致结构就是下图这样子

第二步软中断在合适的时机得以执行,看一下他的执行过程:

static void net_rx_action(struct softirq_action *h)
{struct softnet_data *queue = &__get_cpu_var(softnet_data);unsigned long start_time = jiffies;//预算,所有网卡的总配额int budget = netdev_budget;void *have;local_irq_disable();while (!list_empty(&queue->poll_list)) {struct net_device *dev;//预算用完了,或者时间太长了,跳出等下一轮处理if (budget <= 0 || jiffies - start_time > 1)goto softnet_break;local_irq_enable();dev = list_entry(queue->poll_list.next,struct net_device, poll_list);have = netpoll_poll_lock(dev);if (dev->quota <= 0 || dev->poll(dev, &budget)) {netpoll_poll_unlock(have);local_irq_disable();//没处理完,放到队尾准备下次处理,注意是list_move_tai,不是//list_insert_taillist_move_tail(&dev->poll_list, &queue->poll_list);if (dev->quota < 0)dev->quota += dev->weight;elsedev->quota = dev->weight;} else {netpoll_poll_unlock(have);dev_put(dev);local_irq_disable();}}//省略部分代码
}

软中断不能长时间占用CPU,否则会造成用户态进程长时间得不到调度,net_rx_action也一样。所以net_rx_action函数每次执行最多会处理budget个数据包(所有网卡都算),同时这budget个数据包也需要平均分配,不能只处理一个网卡造成其他网卡得不到处理,net_device的weight和quota是用来处理这个问题的。这个代码的大概意思是每次从poll_list里取出一个网卡,调用该网卡的poll函数尽可能多的收包(但是不会超过weight),poll函数收包后调用netif_receive_skb把数据包放入协议栈。如果网卡里的数据包没处理完就会把net_device继续放到poll_list链表等待下一次软中断继续处理,如果网卡里的数据包处理完了就把该net_device从poll_list摘除。

传统中断收包方式

linux网卡驱动还有部分是用的传统中断收包方式,为了兼容也都挪到了NAPI架构上。用softnet_data结构的backlog_dev伪造了一个net_device。中断发生的时候把数据包放到了softnet_data结构的input_pkt_queue链表里。

static int __init net_dev_init(void)
{
//省略部分代码
        for_each_possible_cpu(i) {struct softnet_data *queue;queue = &per_cpu(softnet_data, i);skb_queue_head_init(&queue->input_pkt_queue);queue->completion_queue = NULL;INIT_LIST_HEAD(&queue->poll_list);set_bit(__LINK_STATE_START, &queue->backlog_dev.state);queue->backlog_dev.weight = weight_p;queue->backlog_dev.poll = process_backlog;atomic_set(&queue->backlog_dev.refcnt, 1);}
}

软中断的处理过程和NAPI类似。

转载于:https://www.cnblogs.com/4a8a08f09d37b73795649038408b5f33/p/11475249.html

linux网络收包过程相关推荐

  1. linux内核网络收包过程—硬中断与软中断

    目录 硬中断处理 软中断处理 数据通过网络发送过来 硬中断处理 数据帧首先到达网卡的接收队列,分配RingBuffer DMA把数据搬运到网卡关联的内存 网卡向CPU发起硬中断,通知CPU有数据 调用 ...

  2. Linux网络数据包接收处理过程

    因为要对百万.千万.甚至是过亿的用户提供各种网络服务,所以在一线互联网企业里面试和晋升后端开发同学的其中一个重点要求就是要能支撑高并发,要理解性能开销,会进行性能优化.而很多时候,如果你对Linux底 ...

  3. Linux网络 - 数据包的接收过程

    Linux网络 - 数据包的接收过程 嵌入式Linux中文站 嵌入式Linux中文站 微信号 emblinux 功能介绍 嵌入式Linux中文站提供专业嵌入式Linux开发技术资讯 Table of ...

  4. 代码学习-Linux内核网卡收包过程(NAPI)

    本文通过学习RealTek8169/8168/8101网卡的驱动代码(drivers/net/r8169.c).梳理一下Linux下网卡的收包过程. 在下水平相当有限,有不当之处,还请大家斧正^_^ ...

  5. Linux网络数据包的揭秘以及常见的调优方式总结

    Linux网络数据包的揭秘以及常见的调优方式总结 (网易游戏运维平台) 关注我们,获一手游戏运维方案 lott 网易游戏业务 SRE, 专注于业务运维的质量和效率 , 喜欢研究 Linux 系统原理. ...

  6. Linux网络 - 数据包的发送过程

    继上一篇介绍了数据包的接收过程后,本文将介绍在Linux系统中,数据包是如何一步一步从应用程序到网卡并最终发送出去的. 如果英文没有问题,强烈建议阅读后面参考里的文章,里面介绍的更详细. 本文只讨论以 ...

  7. Linux网络-数据包的接收流程(基于RTL8139网卡驱动程序)

    本文将介绍Linux系统中,基于RTL8139网卡驱动程序,是如何一步一步将接收到的数据包传送到内核的网络协议栈的. 下图展示了数据包(packet)如何进入内存,并被内核的网络模块开始处理: +-- ...

  8. linux接收网络数据并存存储,linux网络数据包数据结构 Socket Buffer

    Linux网络核心数据结构是套接字缓存(socket buffer),简称skb.它代表一个要发送或处理的报文,并贯穿于整个协议栈.1.套接字缓存skb由两部分组成:(1)报文数据:它保存了实际在网络 ...

  9. 关于Linux 网络抓包的一些笔记整理

    写在前面 遇到一个 ping 单通 的情况,需要抓包分析下,所以整理这部分笔记 博文内容涉及: HTTP/TCP 抓包分析 Demo ICMP 抓包分析 Demo Nginx 抓包分析用户名密码 De ...

最新文章

  1. JetBrains DataGrip工具配置数据库过程详解
  2. Eclipse for android 中设置java和xml代码提示功能(转)
  3. 为了适应云数据库mySQL产品_为了适应不同的应用场景,云数据库mysql版提供的产品系列包括哪些...
  4. 我的github网址链接
  5. Android自定义view之事件传递机制
  6. 机器学习代码实战——保存和加载模型(Save and Load Model)
  7. Unity3D之NGUI基础3.1:代码控制UILabel
  8. 腾讯微信惊天漏洞,利用手机号致帐号丢失无法找回!——论个人信息安全与防护...
  9. react-native windows下环境搭建和现阶段开发测试问题汇总(持续更新)
  10. m3u8 TS 解密合并转码mp4,支持在线 ,UC、QQ等本地缓存
  11. 输入半径,求球的表面积和体积
  12. 项目管理IPD产品开发
  13. USB基础书籍资料推荐
  14. Java爬爬之网页去重和代理ip
  15. 无人便利店沿用超高频RFID技术将快速布局全国
  16. ubuntu安装串口工具minicom
  17. 2018 iOS 面试题大全(补充完整版)
  18. Ubuntu-KCF/DSST算法无人机跟踪仿真/实物保姆级教程
  19. 全国计算机等级考试准考证编号(规则)
  20. 带字幕的Youtube

热门文章

  1. node静态服务器优缺点_使用 Node.js 的优势和劣势都有哪些?
  2. 计算机网络子网划分路由配置实验报告,完整的子网划分与路由交换实验报告 珍藏版哦...
  3. oracle创建多个游标,Oracle——游标的创建和使用
  4. 以下表示中 不能用作c语言常量的是0UL,C语言笔试卷.doc
  5. 小程序 const moment = require('moment')_开源小程序精选
  6. asm 5 java,java – 使用ASM(5.x)在字节代码中检测运行时的递归方法调用:howto?
  7. 基于java TCP实现网络通信聊天室《建议收藏附完整源码》
  8. mysql字段是否存在_Mysql判断表字段或索引是否存在
  9. Java 打印目录结构
  10. Spring使用AspectJ开发AOP