Linux内核以太网驱动分析

1.网络接口卡接收和发送数据在Linux内核中的处理流程如下:

1. 网络接口卡(Network Interface Card, NIC)

  • 作用:负责物理层的数据传输,将数据包从网络介质(如以太网线)读取到内存中,或者将内存中的数据包发送到网络介质上。
  • 过程
    • 接收数据包:当NIC接收到数据包时,它会触发一个中断(ei_interrupt),通知内核有数据包到达。
    • 发送数据包:当NIC需要发送数据包时,它会从内存中读取数据包并通过网络介质发送出去。

2. 中断处理(ei_interrupt

  • 作用:处理NIC触发的中断,将接收到的数据包传递给内核协议栈。
  • 过程
    • 当NIC接收到数据包时,会触发ei_interrupt中断处理程序。
    • 中断处理程序会将数据包封装成一个SKB(Socket Buffer),并将其传递给内核协议栈进行进一步处理。

3. Socket Buffer(SKB)

  • 作用SKB是Linux内核中用于存储网络数据包的数据结构,它包含了数据包的头部信息和数据内容。
  • 过程
    • 在接收数据包时,ei_interrupt会将数据包封装成SKB
    • 在发送数据包时,ei_start_xmit会从SKB中读取数据包并传递给NIC进行发送。

4. 内核协议栈(Kernel Protocol Stack)

  • 作用:负责处理网络协议(如TCP/IP),对数据包进行解析、封装和转发。
  • 过程
    • 接收数据包:从SKB中读取数据包,进行协议解析和处理,然后将数据传递给用户空间的应用程序。
    • 发送数据包:从用户空间的应用程序接收数据,进行协议封装,然后将数据包封装成SKB并传递给NIC进行发送。

5. 用户空间应用程序(User Space Application)

  • 作用:运行在用户空间的应用程序,与网络进行交互。
  • 过程
    • 接收数据包:从内核协议栈接收数据包,进行应用层处理。
    • 发送数据包:将数据传递给内核协议栈,进行网络传输。

6. ei_start_xmit

  • 作用:负责将数据包从内核协议栈传递给NIC进行发送。
  • 过程
    • 当内核协议栈需要发送数据包时,会调用ei_start_xmit函数。
    • ei_start_xmit会从SKB中读取数据包,并将其传递给NIC进行发送。

7. net_devicehard_start_xmit

  • 作用net_device是Linux内核中表示网络设备的数据结构,hard_start_xmitnet_device中的一个函数指针,用于实际的数据包发送操作。
  • 过程
    • ei_start_xmit需要发送数据包时,会调用net_device中的hard_start_xmit函数。
    • hard_start_xmit会将数据包传递给NIC进行实际的发送操作。

        Linux内核直接把中断分成了两个部分:中断上半部和中断下半部。 

在Linux内核中,中断处理被分为两个部分:中断上半部(Top Half)和中断下半部(Bottom Half)。这种设计的主要目的是为了提高系统的响应速度和效率,避免在中断处理过程中长时间占用CPU,导致其他任务无法执行。下面是对这两个部分的详细讲解:

1. 中断上半部(Top Half)

  • 作用:处理中断的紧急部分,确保系统的实时性和响应速度。
  • 特点
    • 优先级高:中断上半部的优先级非常高,可以立即抢占其他任务的执行。
    • 执行时间短:中断上半部的执行时间非常短,通常只进行一些简单的操作,如保存现场、读取硬件状态等。
    • 不能睡眠:中断上半部不能执行任何可能引起睡眠的操作,如等待I/O完成、申请内存等。
  • 过程
    • 当硬件设备(如网络接口卡)触发中断时,CPU会立即停止当前任务的执行,转而执行中断上半部的处理程序。
    • 中断上半部会进行一些紧急的操作,如保存现场、读取硬件状态、记录中断信息等。
    • 完成紧急操作后,中断上半部会立即返回,继续执行被中断的任务。

2. 中断下半部(Bottom Half)

  • 作用:处理中断的非紧急部分,完成中断的后续处理工作。
  • 特点
    • 优先级低:中断下半部的优先级较低,不会立即抢占其他任务的执行。
    • 执行时间长:中断下半部的执行时间较长,可以进行一些复杂的操作,如数据处理、内存申请等。
    • 可以睡眠:中断下半部可以执行可能引起睡眠的操作,如等待I/O完成、申请内存等。
  • 过程
    • 中断上半部在完成紧急操作后,会将一些后续处理工作交给中断下半部。
    • 中断下半部会在适当的时候(如当前任务执行完毕、系统空闲时)被调度执行。
    • 中断下半部会进行一些复杂的操作,如数据处理、内存申请等,完成中断的后续处理工作。

2.Linux内核网络设备驱动框架分为四个模块,分别为网络协议接口模块、网络设备接口模块、设备驱动功能模块、网络设备与媒介模块。

1. 网络协议接口模块
  • dev_queue_xmit(): 这个函数负责将数据包从协议层传递到设备层。它会调用设备驱动程序的发送函数,将数据包放入设备的发送队列中。
  • netif_rx(): 这个函数负责将数据包从设备层传递到协议层。它通常在中断处理程序中被调用,将接收到的数据包传递给协议栈进行处理。
2. 网络设备接口模块
  • net_device结构体类型: 这是Linux内核中表示网络设备的数据结构。它包含了设备的各种属性和方法,如设备名、硬件地址、发送和接收函数等。这个结构体是连接协议层和设备层的关键。
3. 网络驱动功能模块
  • hard_start_xmit(): 这是设备驱动程序中的发送函数。它负责将数据包从设备的发送队列中取出,并将其发送到物理设备上。
  • 中断处理: 当物理设备接收到数据包时,会产生中断。中断处理程序会调用netif_rx()函数,将接收到的数据包传递给协议栈进行处理。
4. 网络设备与媒介模块
  • 网络物理设备: 这是实际的网络硬件设备,如网卡、无线网卡等。它负责将数据包转换为电信号或无线信号,并通过物理媒介(如网线、无线信号)进行传输。

3.网络协议接口模块:

        主要功能给上层协议提供透明的数据包发送和接收的接口,dev_queue_xmit()用于发送数据包,netif_rx()/netif_recieve_skb()用于接收数据包。不管是发送还是接收数据包都会使用到sk_buff结构体类型(套接字缓冲区),主要用在网络子系统中别的各层之间传输数据。

1. 数据包发送接口 dev_queue_xmit

功能与原型
  • 功能:将构造好的数据包(sk_buff)加入发送队列,最终由底层驱动通过ndo_start_xmit方法发送。
  • 原型
  int dev_queue_xmit(struct sk_buff *skb);
  • 参数:skb为包含待发送数据的缓冲区指针。
  • 返回值:0表示成功加入队列,负值表示失败。
使用步骤
  1. 构造sk_buff:需填充协议头(如IP、TCP/UDP)和数据内容,并关联网络设备(skb->dev)。
  2. 调用发送接口
   struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
   // 填充skb数据(如通过skb_put、skb_push等)
   skb->dev = dev; // 关联网络设备
   int ret = dev_queue_xmit(skb);
   if (ret < 0) {
       // 错误处理(如释放skb)
   }
  • 注意dev_queue_xmit最终调用驱动实现的ndo_start_xmit函数完成实际发送。

2. 数据包接收接口 netif_rx

功能与原型
  • 功能:将底层驱动接收到的数据包(sk_buff)提交给协议栈处理。
  • 原型
  int netif_rx(struct sk_buff *skb);
  • 参数:skb为包含接收数据的缓冲区指针。
  • 返回值:表示接收队列状态(如NET_RX_SUCCESSNET_RX_DROP)。
使用步骤
  1. 分配并填充sk_buff
   struct sk_buff *skb = dev_alloc_skb(len + 2); // 分配缓冲区
   if (!skb) {
       // 内存不足处理
       return;
   }
   skb_reserve(skb, 2);    // 预留协议头空间
   // 从硬件读取数据到skb->data
   skb_put(skb, len);       // 设置数据长度
   skb->protocol = eth_type_trans(skb, dev); // 设置协议类型(如ETH_P_IP)[[15, 18]]
  1. 提交到协议栈
   int result = netif_rx(skb);
   if (result == NET_RX_DROP) {
       // 数据包被丢弃处理
   }
  • 注意:调用netif_rx后,驱动不可再访问skb,协议栈会接管其生命周期。

功能和作用

  1. 数据包封装与解封装sk_buff 结构体用于封装和解封装网络数据包,包括各种网络协议头(如MAC头、网络层头、传输层头等)。
  2. 数据包传输:在网络栈中,数据包在不同层之间传递时,sk_buff 结构体作为数据包的载体,确保数据包在传输过程中的完整性和一致性。
  3. 数据包管理sk_buff 结构体还包含了数据包的长度、引用计数、缓存区管理等信息,用于数据包的管理和调度。
  4. 网络协议处理:在数据包的发送和接收过程中,sk_buff 结构体用于存储和处理各种网络协议相关的数据和状态信息 

1. alloc_skb

功能

alloc_skb 是一个用于分配网络缓冲区(sk_buff)的函数。它是一个方便的封装函数,用于简化 _alloc_skb 的调用。alloc_skb 会根据指定的大小和优先级分配一个 sk_buff 结构体。

参数
  • size: 需要分配的缓冲区大小。
  • priority: 分配掩码,用于指定分配的优先级。
使用案例
#include <linux/skbuff.h>

static inline struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
{
    return __alloc_skb(size, priority, 0, NUMA_NO_NODE);
}

// 使用示例
struct sk_buff *skb = alloc_skb(1024, GFP_ATOMIC);
if (skb) {
    // 成功分配了缓冲区,可以进行后续操作
    // ...
    kfree_skb(skb); // 使用完毕后释放缓冲区
}

2. dev_alloc_skb

功能

dev_alloc_skb 是一个用于分配网络设备缓冲区的函数。它是一个遗留的辅助函数,用于简化 netdev_alloc_skb 的调用。

参数
  • length: 需要分配的缓冲区长度。
使用案例
#include <linux/skbuff.h>

static inline struct sk_buff *dev_alloc_skb(unsigned int length)
{
    return netdev_alloc_skb(NULL, length);
}

// 使用示例
struct sk_buff *skb = dev_alloc_skb(1024);
if (skb) {
    // 成功分配了缓冲区,可以进行后续操作
    // ...
    kfree_skb(skb); // 使用完毕后释放缓冲区
}

3. netdev_alloc_skb

功能

netdev_alloc_skb 是一个用于分配网络设备缓冲区的函数。它根据指定的网络设备和长度分配一个 sk_buff 结构体。

参数
  • dev: 指定的网络设备。
  • length: 需要分配的缓冲区长度。
使用案例
#include <linux/skbuff.h>

static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, unsigned int length)
{
    return netdev_alloc_skb(dev, length, GFP_ATOMIC);
}

// 使用示例
struct net_device *dev = ...; // 获取网络设备
struct sk_buff *skb = netdev_alloc_skb(dev, 1024);
if (skb) {
    // 成功分配了缓冲区,可以进行后续操作
    // ...
    kfree_skb(skb); // 使用完毕后释放缓冲区
}

4. struct net_device

功能

struct net_device 是一个用于描述网络设备的结构体。它包含了网络设备的各种属性和配置信息。

字段
  • name: 网络设备的名称。
  • name_node: 网络设备名称节点。
  • ifalias: 网络设备的别名。
  • mem_end: 共享内存的结束地址。
  • mem_start: 共享内存的起始地址。
  • base_addr: 基地址。
  • irq: 中断号。
使用案例
#include <linux/netdevice.h>

// 使用示例
struct net_device *dev = ...; // 获取网络设备

// 打印网络设备的名称
printk(KERN_INFO "Network device name: %s\n", dev->name);

// 打印网络设备的中断号
printk(KERN_INFO "Network device IRQ: %d\n", dev->irq);

5.NAPI 结构体的整体功能

napi_struct结构体是Linux内核中用于网络设备驱动程序的一种机制,旨在优化网络数据包的处理。它的主要功能包括:

  1. 减少中断处理频率:通过将数据包处理从中断上下文转移到轮询上下文,减少中断处理的频率,从而提高系统的性能。
  2. 权重控制:通过设置权重值,控制在一次轮询中可以处理的数据包数量,确保系统资源的合理分配。
  3. 轮询机制:提供一个轮询函数,用于在轮询上下文中处理数据包,避免在中断上下文中进行大量数据包处理。

NAPI 数据包信息的循环流程如下:

  1. 数据接收中断发生:当网络设备接收到数据包时,触发数据接收中断。
  2. 减半接收中断:通过NAPI机制,减少接收中断的频率,将数据包处理转移到轮询上下文。
  3. 以轮询试接收所有数据包或轮询权重耗尽:在轮询上下文中,通过轮询函数处理数据包,直到处理完所有数据包或达到权重限制。
  4. 开启接收中断:当轮询处理完成后,重新开启接收中断,等待下一次数据接收中断的发生。
#include <linux/netdevice.h>
#include <linux/napi.h>

struct my_net_device {
    struct net_device *netdev;
    struct napi_struct napi;
};

static int my_poll(struct napi_struct *napi, int budget)
{
    struct my_net_device *priv = container_of(napi, struct my_net_device, napi);
    int work_done = 0;

    // 处理数据包
    while (work_done < budget) {
        // 从硬件中读取数据包
        struct sk_buff *skb = my_read_skb_from_hardware();

        if (!skb)
            break;

        // 将数据包传递给上层协议栈
        netif_receive_skb(skb);

        work_done++;
    }

    if (work_done < budget) {
        // 如果处理的数据包数量小于预算值,就停止轮询
        napi_complete_done(napi, work_done);
    }

    return work_done;
}

static irqreturn_t my_irq_handler(int irq, void *dev_id)
{
    struct my_net_device *priv = dev_id;

    // 触发轮询
    napi_schedule(&priv->napi);

    return IRQ_HANDLED;
}

static int my_netdev_open(struct net_device *netdev)
{
    struct my_net_device *priv = netdev_priv(netdev);

    // 初始化napi_struct
    netif_napi_add(netdev, &priv->napi, my_poll, 64);

    // 启用中断
    enable_irq(netdev->irq);

    return 0;
}

static int my_netdev_close(struct net_device *netdev)
{
    struct my_net_device *priv = netdev_priv(netdev);

    // 禁用中断
    disable_irq(netdev->irq);

    // 删除napi_struct
    netif_napi_del(&priv->napi);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/980662.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

unity中使用spine详解

一.Spine概述 Spine 是一款针对游戏开发的 2D 骨骼动画编辑工具。 Spine 旨在提供更高效和简洁 的工作流程&#xff0c;以创建游戏所需的动画。 Spine原理&#xff1a;将一个模型&#xff0c;根据动画的需求分成一些骨骼&#xff0c;一个骨骼对应一张贴图&#xff0c;控制骨骼…

【计网】计算机网络概述

第一章 计算机网络概述 1.2 因特网概述1.2.1 网络、互联网和因特网1.2.2 因特网发展的三个阶段1.2.3 因特网的标准化工作1.2.4 因特网的组成 1.3 三种交换方式1.3.1 电路交换1.3.2 分组交换1.3.3 报文交换1.3.4 三种交换的对比 1.4 计网的定义与分类1.4.1 定义1.4.2 分类 1.5 计…

基于Linux系统的物联网智能终端

背景 产品研发和项目研发有什么区别&#xff1f;一个令人发指的问题&#xff0c;刚开始工作时项目开发居多&#xff0c;认为项目开发和产品开发区别不大&#xff0c;待后来随着自身能力的提升&#xff0c;逐步感到要开发一个好产品还是比较难的&#xff0c;我认为项目开发的目的…

[密码学实战]Java实现SM4加解密(ecb,cbc)及工具验证

前言 在现代信息安全领域,数据加密技术是保障数据安全的核心手段之一。SM4作为中国国家密码管理局发布的对称加密算法,因其高效性和安全性,广泛应用于金融、政务、通信等领域。本文将详细介绍如何使用Java实现SM4的加解密操作,并深入探讨SM4的几种常见加密模式及其原理。 …

StableDiffusion本地部署 3 整合包猜想

本地部署和整合包制作猜测 文章目录 本地部署和整合包制作猜测官方部署第一种第二种 StabilityMatrix下载整合包制作流程猜测 写了这么多python打包和本地部署的文章&#xff0c;目的是向做一个小整合包出来&#xff0c;不要求有图形界面&#xff0c;只是希望一键就能运行。 但…

‘ts-node‘ 不是内部或外部命令,也不是可运行的程序

新建一个test.ts文件 let message: string = Hello World; console.log(message);如果没有任何配置的前提下,会报错’ts-node’ 不是内部或外部命令,也不是可运行的程序。 此时需要安装一下ts-node。 npm install

(done) MIT6.S081 Interrupts Lecture 学习笔记

url: https://mit-public-courses-cn-translatio.gitbook.io/mit6-s081/lec09-interrupts/9.1-memory-in-real-os 9.1 真实操作系统内存使用情况 今天课程的内容是中断。但是在具体介绍中断之前&#xff0c;我想先回顾一下上周一些有趣的内容。因为上周的课程主要是讲内存&…

40岁开始学Java:Java中单例模式(Singleton Pattern),适用场景有哪些?

在Java中&#xff0c;单例模式&#xff08;Singleton Pattern&#xff09;用于确保一个类只有一个实例&#xff0c;并提供全局访问点。以下是详细的实现方式、适用场景及注意事项&#xff1a; 一、单例模式的实现方式 1. 饿汉式&#xff08;Eager Initialization&#xff09; …

【计算机网络基础】-------计算机网络概念

1.什么是计算机网络 定义&#xff1a; 图解&#xff1a; 2.最简单的计算机网络 其中&#xff1a; 结点可以是计算机、集线器、交换机、路由器等链路可以是有线链路、无线链路 2.1集线器 2.2交换机 3.互连网&#xff08;internet&#xff09;与 路由器 路由器 与 家用路由…

Qt 自带颜色属性

Qt 系统自带颜色如下&#xff1a; enum GlobalColor {color0,color1,black,white,darkGray,gray,lightGray,red,green,blue,cyan,magenta,yellow,darkRed,darkGreen,darkBlue,darkCyan,darkMagenta,darkYellow,transparent};对应颜色如下&#xff1a; color0: 这是自定义颜色…

数据结构(初阶)(七)----树和二叉树(前中后序遍历)

实现链式结构的二叉树 实现链式结构的二叉树遍历前序遍历中序遍历后序遍历 节点个数叶子节点个数⼆叉树第k层结点个数⼆叉树的深度/⾼度查找值为X的节点二叉树的销毁 层序遍历判断二叉树是否为完全二叉树 ⽤链表来表⽰⼀棵⼆叉树&#xff0c;即⽤链来指⽰元素的逻辑关系。 通常…

哔哩哔哩IT私塾python爬虫视频教程中的项目文件

视频链接&#xff1a; Python课程天花板,Python入门Python爬虫Python数据分析5天项目实操/Python基础.Python教程_哔哩哔哩_bilibili 视频教程中要访问的链接&#xff1a; 豆瓣电影 Top 250 httpbin.org seo推广公司网站模板_站长素材 Examples - Apache ECharts WordCloud…

实验:k8s+keepalived+nginx+iptables

1、创建两个nginx的pod&#xff0c;app都是nginx nginx1 nginx2 2、创建两个的pod的service 3、配置两台keepalived的调度器和nginx七层反向代理&#xff0c;VIP设置192.168.254.110 keepalived调度器master keepalived调度器backup 两台调度器都配置nginx七层反向代理&#…

【Cadence仿真学习笔记】ADS Dynamic Link报错model is reserved的解决办法

首先创建好原理图 创建symbol 在library manager下就会出现symbol了 在Cadence的CIW窗口中运行ADS dynamic link 打开ADS后&#xff0c;创建对应的cellview 加入控件OPTIONS 加入网表netlist 这个时候的Netlist没有路径 点击加载symbol 把原来的netlist include删掉…

【星云 Orbit • STM32F4】06. 串口密码:USART 数据传递

1. 引言 STM32F407是一款高性能的微控制器&#xff0c;具有丰富的外设和强大的处理能力。串口&#xff08;USART&#xff09;是STM32F407的重要外设之一&#xff0c;广泛应用于数据通信、调试和控制等领域。本教程旨在帮助小白从零开始&#xff0c;手动配置STM32F407的串口功能…

Win32 C++ 电源计划操作

CPowerCfgUtils.h #pragma once#include <Windows.h> #include <powrprof.h>// https://learn.microsoft.com/zh-cn/windows/win32/api/powrprof/?sourcerecommendations//节能 //DEFINE_GUID(GUID_MAX_POWER_SAVINGS, 0xA1841308, 0x3541, 0x4FAB, 0xBC, 0x81, …

MySQL—使用binlog日志恢复数据

一、binlog日志恢复数据简介 在 MySQL 中&#xff0c;使用二进制日志&#xff08;binlog&#xff09;恢复数据是一种常见的用于故障恢复或数据找回的方法。以下是详细的使用步骤&#xff1a; 确认 binlog 已启用&#xff1a;首先需要确认 MySQL 服务器已经启用了二进制日志功…

基于springboot+vue实现的宠物救助及领养平台(源码+L文+ppt)43-21

摘 要 宠物救助及领养平台是一个专注于宠物保护和幸福的在线平台。它致力于连接那些需要帮助的宠物与愿意给予它们关爱的家庭。通过这个平台&#xff0c;人们可以报告丢失的宠物、寻求救助资源&#xff0c;以及浏览可领养的宠物信息。该平台不仅提供了一个渠道&#xff0c;让…

人大金仓国产数据库与PostgreSQL

一、简介 在前面项目中&#xff0c;我们使用若依前后端分离整合人大金仓&#xff0c;在后续开发过程中&#xff0c;我们经常因为各种”不适配“问题&#xff0c;但可以感觉得到大部分问题&#xff0c;将人大金仓视为postgreSQL就能去解决大部分问题。据了解&#xff0c;Kingba…

【Java分布式】Nacos注册中心

Nacos注册中心 SpringCloudAlibaba 也推出了一个名为 Nacos 的注册中心&#xff0c;相比 Eureka 功能更加丰富&#xff0c;在国内受欢迎程度较高。 官网&#xff1a;https://nacos.io/zh-cn/ 集群 Nacos就将同一机房内的实例划分为一个集群&#xff0c;一个服务可以包含多个集…