网卡的RX Ring和TX Ring

1 简介

环形缓冲(ring buffer)是NIC处理数据包的一种通用数据结构,出现的原因是现代NIC基本使用DMA进行数据传输,作为一种高效简单[1]的数据结构,环形缓冲很

适合这种大吞吐的场景。在NIC中分成了RX Ring和TX Ring两种缓冲,分别负责接收和传输数据包。环形缓冲的使用维护涉及到NIC硬件、驱动、DMA控制器三

方。接下来的内容将以环形缓冲的组成和代码示例去讲解RX Ring和TX Ring。

2 Ring Buffer的组成

从整体上讲,Ring Buffer由NIC上的一组寄存器(基地址寄存器、长度寄存器、Head寄存器和Tail寄存器)来描述,同时Buffer的空间则是通过在驱动初始化的时

候通过DMA接口分配,而具体的操作是通过一个叫做包描述符的数据结构完成。

网卡的RX Ring和TX Ring

图2-1 Ring Buffer结构图

2.1 包描述符

描述符(Packet Descriptor)用来表达一个数据包在缓冲区内的地址以及数据包在NIC中的状态(是否有异常发生)。这是一个硬件相关的数据结构,由NIC去规定该

结构的内容。描述符分成了接收描述符 (rx descriptor) 和传输描述符 (tx descriptor) 接收描述符是一个用来描述网卡接收的数据缓冲区首地址和硬件用于存储包信

息的数据结构。如下图所示是Intel 8254x系统NIC的接收描述符的结构,共64位。Buffer Address是NIC DMA 数据包的地址,灰色的部门是一些状态字段,这些

字段在NIC接收到数据包之后通过DMA直接进行修改。

网卡的RX Ring和TX Ring

描述符实际存放的位置在驱动分配的DMA内存中,在驱动的Open接口(即启用该设备的时候)进行分配。在i40e中通过调用dma_alloc_coherent完成。

rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size, &rx_ring->dma, GFP_KERNEL);

i40e 使用共用体 i40e_rx_desc 表示一个接收描述符, 在open阶段驱动会给每个描述符分配一个pkt_addr,NIC用该地址作为DMA数据包的起始地址。当包完

整的接收到DMA内存中后,NIC又会通过该描述符设置状态。值得注意的是这些操作都是通过NIC固件完成的。在i40e_rx_desc 中,pkt_addr表示缓冲区DMA的

首地址;wb结构是NIC完成和DMA的包传输之后,向内存中写入的状态,rss_hash是NIC计算的哈

希。

union i40e_32byte_rx_desc {
    struct {
        __le64  pkt_addr; /* Packet buffer address */
        __le64  hdr_addr; /* Header buffer address */
            /* bit 0 of hdr_buffer_addr is DD bit */
        __le64  rsvd1;
        __le64  rsvd2;
    } read;
    struct {
        struct {
            struct {
                union {
                    __le16 mirroring_status;
                    __le16 fcoe_ctx_id;
                } mirr_fcoe;
                __le16 l2tag1;
            } lo_dword;
            union {
                __le32 rss; /* RSS Hash */
                __le32 fcoe_param; /* FCoE DDP Context id */
                /* Flow director filter id in case of
                 * Programming status desc WB
                 */
                __le32 fd_id;
            } hi_dword;
        } qword0;
        struct {
            /* status/error/pktype/length */
            __le64 status_error_len;
        } qword1;
        struct {
            __le16 ext_status; /* extended status */
            __le16 rsvd;
            __le16 l2tag2_1;
            __le16 l2tag2_2;
        } qword2;
        struct {
            union {
                __le32 flex_bytes_lo;
                __le32 pe_status;
            } lo_dword;
            union {
                __le32 flex_bytes_hi;
                __le32 fd_id;
            } hi_dword;
        } qword3;
    } wb;  /* writeback */
};

2.2 寄存器

上一节讲过环形缓冲通过NIC中一组寄存器去表示,本节我们就这些寄存器进行更详细的讨论。就rx而言,一共有四个寄存器,

网卡的RX Ring和TX Ring

图2-1 NIC RX Ring结构图(来自Intel文档)

描述符缓冲的基地址通过两个寄存器表示,分别是 RDBAL(Receive Descriptor Base Address Low) 用来表示 64bit 描述符基地址的低32位,类似的,

RDBAH(Receive Descriptor Base Address High) 表示 64bit 描述符基地址的高32位。 注意这里需要区分下,NIC在内存分配了两种缓冲区,一个是用于存储数据

包,一个用于存储描述符,这里的寄存器表示的都是描述符缓冲区的地址。

网卡的RX Ring和TX Ring

接受描述符长度寄存器,该值需要128字节(最大的cache line大小)对齐

网卡的RX Ring和TX Ring

接收描述符头指针寄存器,该寄存器是通过硬件控制。

网卡的RX Ring和TX Ring

接收描述符尾指针寄存器

网卡的RX Ring和TX Ring

2.3 数据包缓冲区

至此环形缓冲的内容就结束了,实际上环形缓冲指的是描述符的缓冲,真正存储数据包的起始地址存在描述符中。一个缓冲有一个对skb的引用,dma内存的地

址,和对物理页的引用构成。

struct i40e_rx_buffer {
    dma_addr_t dma;
#ifdef CONFIG_I40E_DISABLE_PACKET_SPLIT
    struct sk_buff *skb;
#else
    struct page *page;
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)
    __u32 page_offset;
#else
    __u16 page_offset;
#endif
    __u16 pagecnt_bias;
#endif /* CONFIG_I40E_DISABLE_PACKET_SPLIT */
};

参考

https://stackoverflow.com/questions/36625892/descriptor-concept-in-nic

https://en.wikipedia.org/wiki/Circular_buffer

https://wenfh2020.com/2021/12/29/kernel-tcp-receive/

网卡的RX Ring和TX Ring

本作品采用
知识共享署名 4.0 国际许可协议

进行许可。

Original: https://www.cnblogs.com/dennis-wong/p/16326890.html
Author: 成蹊0xc000
Title: 网卡的RX Ring和TX Ring

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/582762/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Go语言中的零值坑记

    开箱即用 什么叫开箱即用呢?因为 Go语言的零值让程序变得更简单了,有些场景我们不需要显示初始化就可以直接用,举几个例子: 切片,他的零值是 nil,即使不用 make进行初始化也…

    Linux 2023年6月6日
    0119
  • CSAPP 之 AttackLab 详解

    前言 本篇博客将会介绍 CSAPP 之 AttackLab 的攻击过程,利用缓冲区溢出错误进行代码注入攻击和 ROP 攻击。实验提供了以下几个文件,其中 ctarget 可执行文件…

    Linux 2023年6月7日
    0101
  • linux man 中文手册安装

    Linux Man (手册) linux man 中文手册安装 步骤 下载源程序 解压文件并进入该目录 unzip master.zip ;cd master 安装支持程序 sud…

    Linux 2023年6月7日
    084
  • Redisson实现分布式锁源码解读

    文章目录 一、分布式锁的概念 和 使用场景 二、将redis官网对于分布式锁(红锁)的定义和Redisson实现做概括性总结 三、基于Redisson的分布式实现方案 四、加锁过程…

    Linux 2023年5月28日
    086
  • OpenStack-iaas之“先点”云平台安装

    1.认识OpenStack 1.云计算的起源 早在2006年3月,亚马逊公司首先提出弹性计算云服务。2006年8月9日,谷歌公司首席执行官埃里克·施密特(Eric Schmidt)…

    Linux 2023年6月13日
    091
  • 对象缓存服务的思考和实现

    写在前面 目前在很多业务中,存储都大量的依赖了云存储,比如阿里云的 oss、华为云的 obs 等。但是如果有大量的上传/下载任务,云存储上的网络 I/0 就变成了一个很大的瓶颈。 …

    Linux 2023年6月14日
    096
  • Linux磁盘管理

    一、磁盘管理 Linux 磁盘管理好坏直接关系到整个系统的性能问题。 Linux 磁盘管理常用的三个命令为 df、 du 和 fdisk。 df(英文全称:disk full):列…

    Linux 2023年5月27日
    0100
  • linux版的查毒工具 ClamAv 安装脚本

    /bin/bash 安装linux版的查毒工具 clamav 用root执行 保证服务器能访问外网 yum源最好是最新的 创建用户和组 groupadd clamavuseradd…

    Linux 2023年6月13日
    0106
  • 剑指offer计划20( 搜索与回溯算法中等)—java

    1.1、题目1 剑指 Offer 07. 重建二叉树 1.2、解法 注释解法。 1.3、代码 class Solution { int[] preorder; HashMap ma…

    Linux 2023年6月11日
    0104
  • Mysql数据库语言学习的路线

    对于我们数据库的学习,不管是测试人员还是开发人员以及我们的DBA来说重点都是SQL;但是我们的SQL可以分多少类型,学习重点又是在哪里呢,本文仅仅针对测试人员来展开说明: SQL:…

    Linux 2023年6月14日
    089
  • JavaScript快速入门-04-运算符

    4 运算符 4.1 算术运算符 4.1.1 概述 JavaScript 提供的算术运算符如下所示: 类型 符号 示例 加法运算符 + a+b 减法运算符 – a-b 乘…

    Linux 2023年6月7日
    075
  • 关于建设博客的事

    今天晚上到教室之后看到好多人在写简历,都在为周六的招聘会而准备,看了旁边同学的简历,里面有个个人网站,我点开一看是他的掘金博客,我突然想到了我老早之前注册的博客园的账号,一篇文章也…

    Linux 2023年6月7日
    0107
  • Centos7 禁用IPV6地址的方法

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月7日
    083
  • Spring事务(二)-事务传播行为

    在Spring里,一个事务方法被另外一个事务方法调用时,两个方法的事务应该如何进行,说白话一点,就是说当出现异常需要回滚时,各个方法的数据操作是否要全部回滚,事务传播行为就是决定了…

    Linux 2023年6月6日
    083
  • C语言基本语法

    C语言以分号代表一条语句结束,一条命令可以在多行显示 对于空格没有多大要求,只是为了代码美观,方便看懂,但python语法就比较严格必须要加空格 注释VS快捷键Ctrl+K,然后C…

    Linux 2023年6月8日
    098
  • 关于.NET CORE 编译时错误:Microsoft.AspNetCore.Razor.Design.CodeGeneration.targets(79, 5): The project XXXXX must provide a value for Configuration.

    此笔记记载了本人在编译.Net Core项目时遇到的 Microsoft.AspNetCore.Razor.Design.CodeGeneration.targets(79, 5)…

    Linux 2023年6月14日
    0111
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球