版本说明

Linux版本: 3.10.103
网卡驱动: ixgbev

报文收发简单流程

网卡驱动默认采用的是NAPI的报文处理方式。即中断+轮询的方式,网卡收到一个报文之后会产生接收中断,并且屏蔽中断,直到收够了netdev_max_backlog个报文(默认300)或者收完网卡上的所有报文之后,重新打开中断。

网卡数据处理

网卡初始化

  • 内核启动时会调用do_initcalls,从而调用注册的初始化接口net_dev_init,net_dev_init注册软中断的回调函数,分别为接收和发送的:NET_RX_SOFTIRQ = net_rx_action,NET_TX_SOFTIRQ = net_tx_action。
  • 网卡驱动加载时调用ixgbe_init_module注册一个PCI驱动。
  • 接着调用probe对应的ixgbe_probe做一些准备工作如下:
    • 创建ixgbe_adapter数据结构,这是网卡的一个实例,其中包含了网卡的所有数据和接口(netdev)。
    • netdev注册了网卡的所有操作:ixgbe_netdev_ops和网卡的features。
    • ixgbe_init_interrupt_scheme主要是设置网卡的NAPI对应的poll接口,这里主要是ixgbe_poll。
  • 网卡激活时会调用netdev上的open函数ixgbe_open,完成工作如下:
    • 设置接收和发送队列,通过DMA讲PCI网卡地址和队列建立映射。
    • 给网卡注册硬中断:ixgbe_open–>ixgbe_request_irq–>ixgbe_request_msix_irqs注册中断回调ixgbe_msix_clean_rings。(MSIX中断时)
  • ixgbe_close函数所做的事情:
    • 关闭中断并且释放中断向量号。
    • 释放申请的相应空间。

网卡收发数据

  • 当网卡接收到数据帧时,DMA将数据搬运到对应的rx_ring,然后产生一个硬中断,调用接口ixgbe_msix_clean_rings。
  • 硬中断回调函数ixgbe_msix_clean_rings会调用当前CPU对应的NET_RX_SOFTIRQ,即net_rx_action。其中的主要实现NAPI操作如下:
    • 关闭硬中断。
    • 调用该CPU的poll_list中的所有poll函数,即ixgbe_poll。
    • 开启硬中断。
  • 轮询函数ixgbe_poll主要是处理接收发送任务:
    • 循环处理每个ring中的数据,ixgbe_clean_tx_irq,此处发送tx_work_limit个报文(128)或者没有报文后完成,并且调用netif_wake_subqueue触发发送软中断NET_TX_SOFTIRQ,即net_tx_action。
    • 循环处理每个ring中的数据,ixgbe_clean_rx_irq,此处接收weight个报文(64),总共收取netdev_budget(300)个,并且调用ixgbe_rx_skb进行下一步的处理。
  • ixgbe_rx_skb最终会处理过GRO之后调用到netif_receive_skb,此处忽略rps。
  • netif_receive_skb最终调用__netif_receivve_skb_core进入协议栈处理各种协议。
    • 首先根据下面介绍的rx_handler类型调用ovs或者桥处理函数进入L2的处理。
    • 然后根据pttype_base处理相关的L3协议处理。

备注

  • ixgbe拥有64个rx_ring,每个ring默认有512个buffer,最小64,最大4096。
  • 由以上可知网卡默认可以缓存32768个报文,当网卡接收报文的速度过快,接收软中断无法处理的时候,系统进入扼流(throttle)状态,所有后续的报文都被丢弃,直到rx_ring有空间了。
  • 通过DMA地址映射的方式,网卡接收数据相当于零拷贝。

TUN虚拟网卡

  • 网卡驱动加载时调用tun_init注册一个MISC驱动,生成/dev/net/tun的设备文件。
  • 接着调用open对应的tun_chr_open做主要创建socket。
  • 随后调用ioctl对应的tun_chr_ioctl,完成一些需要的配置和信息获取,包括校验、连接状态、offload、mac等。
  • 通过调用write发送报文,主要是调用tun_chr_aio_write生成skb格式报文,最终通过调用netif_rx进入协议栈,通过三层转发到对应的端口发送。
  • 通过调用read接收报文,主要是调用tun_chr_aio_read,从内核对应的sock队列上拿到报文,然后将数据上传到用户层。

注:
因为网卡接收报文后最终经过四层的时候,会将报文根据协议几元组找到对应的sock结构,放入队列。上层调用read或者recv的时候都是从socket对应的sock结构队列上取数据。

tun虚拟网卡流程图:

VETH虚拟网卡

  • 网卡驱动加载时调用veth_init注册一个netlink驱动。
  • 接着调用newlink对应的veth_newlink,创建两个网络设备,两者互为对方的peer。
  • 发送报文时会调用ndo_start_xmit对应的veth_xmit,实际操作为将skb的dev设置为自己的peer,调用到netif_rx接收到协议栈。

veth虚拟网卡示意图:

QEMU虚拟机网络通信

  • 主机vhost驱动加载时调用vhost_net_init注册一个MISC驱动,生成/dev/vhost-net的设备文件。

  • 主机qemu-kvm启动时调用open对应的vhost_net_open做主要创建队列和收发函数的挂载,接着调用ioctl启动内核线程vhost,做收发包的处理。

  • 主机qemu通过ioctl配置kvm模块,主要设置通信方式,因为主机vhost和virtio只进行报文的传输,kvm进行提醒。

  • 虚拟机virtio模块注册,生成虚拟机的网络设备,配置中断和NAPI。

  • 虚拟机发包流程如下:

    • 直接从应用层走协议栈最后调用发送接口ndo_start_xmit对应的start_xmit,将报文放入发送队列,vp_notify通知kvm。
    • kvm通过vmx_handle_exit一系列调用到wake_up_process唤醒vhost线程。
    • vhost模块的线程激活并且拿到报文,在通过之前绑定的发送接口handle_tx_kick进行发送,调用虚拟网卡的tun_sendmsg最终到netif_rx接口进入主机内核协议栈。
  • 虚拟机收包流程如下:

    • tap设备的ndo_start_xmit对应的tun_net_xmit最终调用到wake_up_process激活vhost线程,调用handle_rx_kick,将报文放入接收队列。
    • 通过一系列的调用到kvm模块的接口kvm_vcpu_kick,向qemu虚拟机注入中断。
    • 虚拟机virtio模块中断调用接口vp_interrupt,调用virtnet_poll,再调用到netif_receive_skb进入虚拟机的协议栈。

qemu虚拟机通信流程图:

Offload技术

发送数据

  • TSO(TCP Segmentation Offload)使得网络协议栈能够将大块buffer推送至网卡,然后网卡执行分片工作,这样减轻了CPU的负荷,但TSO需要硬件来实现分片功能,也叫LSO。
  • UFO(UDP Fragmentation Offload)类似。
  • GSO(Generic Segmentation Offload),它比TSO更通用,基本思想就是尽可能的推迟数据分片直至发送到网卡驱动之前,此时会检查网卡是否支持分片功能(如TSO、UFO),如果支持直接发送到网卡,如果不支持就进行回调分片后再发往网卡。这样大数据包只需走一次协议栈,而不是被分割成几个数据包分别走,这就提高了效率。

接收数据

  • LRO(Large Receive Offload)通过将接收到的多个TCP数据聚合成一个大的数据包,然后传递给网络协议栈处理,以减少上层协议栈处理开销,提高系统接收TCP数据包的能力。
  • GRO(Generic Receive Offloading),LRO使用发送方和目的地IP地址,IP封包ID,L4协议三者来区分段,对于从同一个SNAT域的两个机器发向同一目的IP的两个封包可能会存在相同的IP封包ID(因为不是全局分配的ID),这样会有所谓的卷绕的bug。GRO采用发送方和目的地IP地址,源/目的端口,L4协议三者来区分作为改进。所以对于后续的驱动都应该使用GRO的接口,而不是LRO。另外,GRO也支持多协议。

原文链接:https://zhaozhanxu.com/2016/07/12/Linux/2016-07-12-Linux-Kernel-Pkts_Processing1/

linux内核网络协议栈--网卡报文收发(十六)相关推荐

  1. linux内核网络协议栈--架构分析(十八)

    1.初始化流程 2.分层数据结构 3.socket创建流程 4.收发流程 5.内核收包流程细化(中断收包) 6.应用层收包流程 7.UDP发包流程 原文链接:https://blog.csdn.net ...

  2. Linux内核网络协议栈流程及架构

    文章目录 Linux内核网络报文处理流程 Linux内核网络协议栈架构 Linux内核网络报文处理流程 linux网络协议栈是由若干个层组成的,网络数据的处理流程主要是指在协议栈的各个层之间的传递. ...

  3. linux网卡发送数据包流程,linux内核Ethernet以太网卡驱动收发数据过程

    linux内核Ethernet以太网卡驱动收发数据过程 linux内核Ethernet以太网卡驱动收发数据过程 下图简单描述了网卡驱动与Linux内核之间的联系: 关于上图的一些说明: 系统初始化: ...

  4. Linux内核网络协议栈:udp数据包发送(源码解读)

    <监视和调整Linux网络协议栈:接收数据> <监控和调整Linux网络协议栈的图解指南:接收数据> <Linux网络 - 数据包的接收过程> <Linux网 ...

  5. 深入浅出Linux内核网络协议栈|结构sk_buff|Iptables|Netfilter丨内核源码丨驱动开发丨内核开发丨C/C++Linux服务器开发

    深入浅出Linux内核网络协议栈 视频讲解如下,点击观看: 深入浅出Linux内核网络协议栈|结构sk C/C++Linux服务器开发高级架构师知识点精彩内容包括:C/C++,Linux,Nginx, ...

  6. Linux 内核网络协议栈运行原理

    封装:当应用程序用 TCP 协议传送数据时,数据首先进入内核网络协议栈中,然后逐一通过 TCP/IP 协议族的每层直到被当作一串比特流送入网络.对于每一层而言,对收到的数据都会封装相应的协议首部信息( ...

  7. linux内核网络协议栈--linux网络设备理解(十三)

    网络层次 linux网络设备驱动与字符设备和块设备有很大的不同. 字符设备和块设备对应/dev下的一个设备文件.而网络设备不存在这样的设备文件.网络设备使用套接字socket访问,虽然也使用read, ...

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

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

  9. linux内核网络协议栈--监控和调优:接收数据(十五)

    译者序 本文翻译自 2016 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Receiving Data.如果能看懂英文,建议阅 ...

最新文章

  1. ∇SLAM:自动可微分SLAM
  2. 从零开始在ubuntu上安装和使用k8s集群及报错解决
  3. lintcode:删除链表中指定元素
  4. boost::math模块演示负二项分布使用的简单示例的测试程序
  5. Visio矢量图导出教程
  6. P4981-父子【数学,树】
  7. Java 11:新的HTTP客户端API
  8. nodejs获得服务器响应,轻松创建nodejs服务器(6):作出响应
  9. 在碎片化阅读充斥眼球的时代,要高效读论文
  10. Mysql 远程自动化备份
  11. 【App 开发框架 - App Framework】
  12. 深度学习常见的基本概念整理
  13. 目标规划第四章计算机求解,单纯形算法与目标规划地应用研究.doc
  14. 仿支付宝手势密码解锁
  15. 使用MoveIt!+Arbotix控制六自由度机械臂
  16. mysql sql语法解析器_Druid SQL 解析器概览
  17. Exponetial BackOff(指数退避算法)
  18. 控制器设计与仿真 实验计算机组成,计算机组成原理——微程序控制器实验
  19. 看完就会使用Nacos-服务发现
  20. tp接入富友H5支付

热门文章

  1. python学了有用吗-为什么要学Python?学了有什么用?
  2. python类装饰器详解-python 中的装饰器详解
  3. 9.9学python靠谱吗-宅家亲测:9.9的python体验课,到底值不值?
  4. java好还是python好-现在学Python还是Java好呢?
  5. python爬虫百度百科-python每日一题:网络爬虫百度百科
  6. LeetCode Valid Number(判断字符串是否是合法的数字表示 )
  7. LeetCode Largest Divisible Subset(动态规划)
  8. linux网络服务器框架转载
  9. vuex分模块后,如何获取state的值
  10. thinkphp联查