网卡

网卡工作在物理层和数据链路层,主要由PHY/MAC芯片、Tx/Rx FIFO、DMA等组成,其中网线通过变压器接PHY芯片、PHY芯片通过MII接MAC芯片、MAC芯片接PCI总线

PHY芯片主要负责:CSMA/CD、模数转换、编解码、串并转换

MAC芯片主要负责:

  • 比特流和帧的转换:7字节的前导码Preamble和1字节的帧首定界符SFD
  • CRC校验
  • Packet Filtering:L2 Filtering、VLAN Filtering、Manageability / Host Filtering

Intel的千兆网卡以82575/82576为代表、万兆网卡以82598/82599为代表

收发包过程图

ixgbe_adapter包含ixgbe_q_vector数组(一个ixgbe_q_vector对应一个中断),ixgbe_q_vector包含napi_struct

硬中断函数把napi_struct加入CPU的poll_list,软中断函数net_rx_action()遍历poll_list,执行poll函数

收包过程


1、网卡驱动创建rx descriptor ring(一致性DMA内存),将rx descriptor ring的总线地址写入网卡寄存器RDBA

2、网卡驱动为每个descriptor分配sk_buff和数据缓存区,流式DMA映射数据缓存区,将数据缓存区的总线地址保存到descriptor

3、网卡接收数据包,将数据包写入Rx FIFO

4、DMA找到rx descriptor ring中下一个将要使用的descriptor

5、整个数据包写入Rx FIFO后,DMA通过PCI总线将Rx FIFO中的数据包复制到descriptor的数据缓存区

6、复制完后,网卡启动硬中断通知CPU数据缓存区中已经有新的数据包了,CPU执行硬中断函数:

  • NAPI(以e1000网卡为例):e1000_intr() -> __napi_schedule() ->__raise_softirq_irqoff(NET_RX_SOFTIRQ)
  • 非NAPI(以dm9000网卡为例):dm9000_interrupt() -> dm9000_rx() -> netif_rx() ->napi_schedule() -> __napi_schedule() ->__raise_softirq_irqoff(NET_RX_SOFTIRQ)

7、ksoftirqd执行软中断函数net_rx_action():

  • NAPI(以e1000网卡为例):net_rx_action() -> e1000_clean() ->e1000_clean_rx_irq() -> e1000_receive_skb() -> netif_receive_skb()
  • 非NAPI(以dm9000网卡为例):net_rx_action() -> process_backlog() ->netif_receive_skb()

8、网卡驱动通过netif_receive_skb()将sk_buff上送协议栈

Rx Ring Buffer

SW向从next_to_use开始的N个descriptor补充sk_buff,next_to_use += N,tail = next_to_use(写网卡寄存器RDT)

HW写Frame到从head开始的M个descriptor的sk_buff,写完后回写EOP(End of Packet),head += M

SW将从next_to_clean开始的L个sk_buff移出Rx Ring Buffer并上送协议栈,next_to_clean += L,向从next_to_use开始的L个descriptor补充sk_buff,next_to_use += L,tail = next_to_use

注意:每次补充完sk_buff后,tail和next_to_use指向同一个sk_buff

发包过程


1、网卡驱动创建tx descriptor ring(一致性DMA内存),将tx descriptor ring的总线地址写入网卡寄存器TDBA

2、协议栈通过dev_queue_xmit()将sk_buff下送网卡驱动

3、网卡驱动将sk_buff放入tx descriptor ring,更新TDT

4、DMA感知到TDT的改变后,找到tx descriptor ring中下一个将要使用的descriptor

5、DMA通过PCI总线将descriptor的数据缓存区复制到Tx FIFO

6、复制完后,通过MAC芯片将数据包发送出去

7、发送完后,网卡更新TDH,启动硬中断通知CPU释放数据缓存区中的数据包

Tx Ring Buffer

SW将sk_buff挂载到从next_to_use开始的N个descriptor,next_to_use += N,tail = next_to_use(写网卡寄存器TDT)

HW使用DMA读从head开始的M个descriptor的sk_buff,发送成功后回写DD(Descriptor Done),head += M

SW将从next_to_clean的开始的L个sk_buff移出Tx Ring Buffer并清理,next_to_clean += L

注意:每次挂载完sk_buff后,tail和next_to_use指向同一个descriptor

中断上下部

do_IRQ()

do_IRQ()是CPU处理硬中断的总入口

// 在e1000_request_irq()中注册硬中断,中断函数为e1000_intr()
irq_handler_t handler = e1000_intr;
err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,netdev);// 在net_dev_init()中注册软中断,中断函数为net_rx_action()
open_softirq(NET_RX_SOFTIRQ, net_rx_action);// 在e1000_probe()中注册napi的poll函数为e1000_clean()
netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);// 在net_dev_init()中注册非napi的poll函数为process_backlog()
queue->backlog.poll = process_backlog;

netif_rx()

在netif_rx()中把skb加入CPU的softnet_data

int netif_rx(struct sk_buff *skb)
{struct softnet_data *queue;unsigned long flags;/* if netpoll wants it, pretend we never saw it */if (netpoll_rx(skb))return NET_RX_DROP;if (!skb->tstamp.tv64)net_timestamp(skb);/** The code is rearranged so that the path is the most* short when CPU is congested, but is still operating.*/local_irq_save(flags);queue = &__get_cpu_var(softnet_data); // 得到CPU的softnet_data__get_cpu_var(netdev_rx_stat).total++;if (queue->input_pkt_queue.qlen <= netdev_max_backlog) { // 若队列长度不大于netdev_max_backlogif (queue->input_pkt_queue.qlen) { // 若队列长度非0,表示queue->backlog已被加入poll_list
enqueue:__skb_queue_tail(&queue->input_pkt_queue, skb); // 将skb加入队列尾部local_irq_restore(flags);return NET_RX_SUCCESS;}napi_schedule(&queue->backlog); // 调度queue->backloggoto enqueue; // 将skb加入队列尾部}__get_cpu_var(netdev_rx_stat).dropped++;local_irq_restore(flags);kfree_skb(skb);return NET_RX_DROP;
}

原文链接:https://blog.csdn.net/hz5034/article/details/79794615?utm_source=copy

linux内核网络协议栈--数据包的网卡驱动收发包过程(二十五)相关推荐

  1. linux内核网络协议栈--数据包的skb桥转发蓝图(二十六)

    话不多说,先看一张桥转发时函数调用的一个基本蓝图. 这张图中,简单的展示了,数据的接收和发送,其中还包括netfilet的钩子点所处的位置. 需要说明的是: 1.我们先暂时忽略数据包从一开始是怎么从驱 ...

  2. linux内核网络协议栈--数据包的网卡缓冲区(二十四)

    程序员可能关心的基本网卡知识 网卡相关介绍:http://www.linuxidc.com/Linux/2012-12/77132.htm 一.什么是网卡? 它是主机的网络设备,本身是LAN(局域网) ...

  3. linux内核网络协议栈--数据包的网卡转发流程(二十七)

    原文链接:https://blog.csdn.net/jackywgw/article/details/78321226

  4. linux内核网络协议栈--数据包的接收过程(二十)

    本文将介绍在Linux系统中,数据包是如何一步一步从网卡传到进程手中的. 本文只讨论以太网的物理网卡,不涉及虚拟设备,并且以一个UDP包的接收过程作为示例. 本示例里列出的函数调用关系来自于kerne ...

  5. linux内核网络协议栈--数据包的发送过程(二十一)

    继上一篇介绍了数据包的接收过程后,本文将介绍在Linux系统中,数据包是如何一步一步从应用程序到网卡并最终发送出去的. socket层 +-------------+| Application |+- ...

  6. linux内核网络协议栈--数据包的接收过程(二十二)

    与其说这篇文章分析了网卡驱动中中数据包的接收,还不如说基于Kernel:2.6.12,以e100为例,对网卡驱动编写的一个说明.当然,对数据包的接收说的很清楚. 一.从网卡说起 这并非是一个网卡驱动分 ...

  7. linux内核网络协议栈--数据包的接收流程(二十三)

    网卡在接受数据包时会产生中断,即当 有一个以太网帧到来时,网卡向内核产生一次中断: CPU收到中断信号后,执行中断处理程序,中断处理程序会设置 缓冲区地址.DMA 地址等信息: 网卡通过DMA 方式将 ...

  8. linux内核网络协议栈--数据包的数据收发简略流程图(二十八)

    基于内核3.17.1版本 原文链接:https://blog.csdn.net/subfate/article/details/53107435

  9. Linux内核网络udp数据包发送(二)——UDP协议层分析

    1. 前言 本文分享了Linux内核网络数据包发送在UDP协议层的处理,主要分析了udp_sendmsg和udp_send_skb函数,并分享了UDP层的数据统计和监控以及socket发送队列大小的调 ...

最新文章

  1. 开发日记-20190918 关键词 努力
  2. 分形树Fractal tree介绍——具体如何结合TokuDB还没有太懂,先记住其和LSM都是一样的适合写密集...
  3. typecho除了首页其他大部分网页404怎么办?
  4. 在webstorm中使用Jade for Meteor,模板template语法“+templateName”不能使用的解决方案...
  5. springboot线程池配置
  6. ajax 请求struts1,jquery ajax +struts1.3
  7. Log4cpp 配置文件配置Syslog
  8. 基于DWM1000的UWB测距调试(一)
  9. php 生成会员卡号,PHP实现生成唯一会员卡号
  10. 深度学习图像识别笔记(二):红外图像
  11. 2019西安邀请赛游记
  12. The Preliminary Contest for ICPC Asia Shanghai 2019 B. Light bulbs(卡了线段树空间的思维题)
  13. 学习【瑞吉外卖①】SpringBoot单体项目
  14. prometheus + grafana 对 springboot 项目进行监控
  15. java excel 饼图_Java 在 Excel 中创建饼图/环形图
  16. STC12系列单片机的AUXR辅助寄存器
  17. asp.net 后台生成二维码及生成带logo的二维码
  18. hibernate之HQL实体更新与删除
  19. word2016加载MathType打开时显示“安全警告,宏已被禁用”解决办法
  20. 如何计算机打开桌面文件,电脑系统奔溃如何找回桌面文件?系统损坏桌面文件如何拷贝出来...

热门文章

  1. python怎么读取文件-python如何读取文件的数据
  2. python零基础电子书免费下载-零基础学Python
  3. 用python画烟花-python实现烟花小程序
  4. python装饰器-究竟什么是装饰器?python中的装饰器介绍
  5. python语言程序设计梁勇-Python语言程序设计(美-梁勇)第1章习题解答
  6. python网络爬虫的基本步骤-详解Python网络爬虫功能的基本写法
  7. python程序打包成exe可执行文件,亲测可行(pyinstaller教程)
  8. python读取 .mat 文件(matlab文件)
  9. WAT中Security选项卡无法连接到数据库解决办法
  10. Django笔记(一)