编写 Linux 网络驱动时,需要关注哪些关键的接口和数据结构?

闪客一族 2025-06-19 15:29:53

编写 Linux 网络驱动时,需要关注哪些关键的接口和数据结构?

...全文
52 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复

在 Linux 内核中开发网络驱动时,需要理解并操作一系列关键的接口和数据结构。这些组件构成了驱动与内核网络子系统之间的桥梁,直接影响驱动的性能和功能。以下是核心接口和数据结构的详细解析:

一、核心数据结构

1. struct net_device

  • 作用:表示一个网络设备的抽象,包含设备的基本信息(如名称、MAC地址)、状态和操作函数集。
  • 关键字段
    struct net_device {
        char name[IFNAMSIZ];           // 设备名称(如eth0)
        unsigned char dev_addr[ETH_ALEN]; // MAC地址
        unsigned int flags;           // 设备标志(如IFF_UP、IFF_RUNNING)
        unsigned int mtu;             // 最大传输单元
        unsigned int tx_queue_len;    // 发送队列长度
        const struct net_device_ops *netdev_ops; // 操作函数集
        struct netdev_queue *_tx;     // 发送队列
        struct netdev_bus_info bus_info; // 总线信息
        // ... 其他字段
    };
    
  • 注意:现代驱动通常使用 alloc_netdev()alloc_etherdev() 动态分配该结构,避免直接操作。

2. struct net_device_ops

  • 作用:定义网络设备的操作函数集,驱动必须实现其中的关键回调函数。
  • 核心函数
    struct net_device_ops {
        int (*ndo_init)(struct net_device *dev);    // 设备初始化
        void (*ndo_uninit)(struct net_device *dev);  // 设备释放
        int (*ndo_open)(struct net_device *dev);    // 设备打开
        int (*ndo_stop)(struct net_device *dev);    // 设备关闭
        netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,  // 发送数据包
                                      struct net_device *dev);
        int (*ndo_set_mac_address)(struct net_device *dev,  // 设置MAC地址
                                   void *addr);
        // ... 其他函数(如多播、VLAN处理等)
    };
    

3. struct sk_buff(Socket Buffer)

  • 作用:内核中表示网络数据包的核心数据结构,贯穿整个网络栈。
  • 关键字段
    struct sk_buff {
        struct sk_buff *next;         // 链表指针
        unsigned char *head, *data, *tail, *end; // 数据缓冲区指针
        unsigned int len, data_len;   // 数据长度
        __be16 protocol;              // 协议类型(如ETH_P_IP)
        struct net_device *dev;       // 关联的网络设备
        // ... 其他字段(如时间戳、VLAN标签、校验和等)
    };
    
  • 注意:驱动负责填充或解析该结构,并通过 netif_rx()napi_gro_receive() 将数据包注入内核。

二、发送路径关键接口

1. ndo_start_xmit()

  • 功能:驱动发送数据包的核心回调函数,当上层协议(如TCP/IP)有数据需要发送时调用。
  • 实现要点
    netdev_tx_t mydriver_start_xmit(struct sk_buff *skb, struct net_device *dev) {
        // 1. 从skb中提取数据和元信息
        unsigned char *data = skb->data;
        unsigned int len = skb->len;
        
        // 2. 硬件操作:将数据写入网卡发送缓冲区
        mydriver_hw_tx(dev, data, len);
        
        // 3. 释放skb(驱动已接管数据)
        dev_kfree_skb(skb);
        
        // 4. 返回发送状态(通常为NETDEV_TX_OK)
        return NETDEV_TX_OK;
    }
    

2. 发送队列管理

  • **netdev_tx_lock()/netdev_tx_unlock()**:锁定/解锁发送队列,确保线程安全。
  • **netif_stop_queue()/netif_wake_queue()**:暂停/恢复发送队列(如网卡忙时暂停队列)。

三、接收路径关键接口

1. 轮询模式(传统方式)

  • **netif_rx()**:将接收到的数据包注入内核网络栈。
    void mydriver_rx_handler(struct net_device *dev, unsigned char *data, int len) {
        // 1. 分配skb
        struct sk_buff *skb = dev_alloc_skb(len + NET_IP_ALIGN);
        if (!skb) return;
        
        // 2. 复制数据到skb
        skb_reserve(skb, NET_IP_ALIGN);
        memcpy(skb_put(skb, len), data, len);
        
        // 3. 设置协议类型和设备
        skb->dev = dev;
        skb->protocol = eth_type_trans(skb, dev);
        
        // 4. 提交到内核
        netif_rx(skb);
    }
    

2. NAPI(New API,高性能方式)

  • 作用:通过轮询替代中断,减少高流量下的中断开销。
  • 关键步骤
    1. 注册NAPI:在驱动初始化时调用 napi_add()
    2. 中断处理:触发中断时调用 napi_schedule() 调度NAPI处理。
    3. 轮询处理:实现 napi_poll() 回调函数处理批量数据包。
      static int mydriver_poll(struct napi_struct *napi, int budget) {
       struct net_device *dev = container_of(napi, struct mydriver, napi);
       int packets = 0;
       
       // 从硬件FIFO读取多个数据包
       while (packets < budget && mydriver_hw_rx_ready(dev)) {
           struct sk_buff *skb = mydriver_fetch_packet(dev);
           if (skb) {
               napi_gro_receive(napi, skb);
               packets++;
           }
       }
       
       // 如果处理完所有数据包,关闭NAPI轮询
       if (!mydriver_hw_rx_ready(dev)) {
           napi_complete(napi);
       }
       
       return packets;
      }
      

四、设备初始化与资源管理

1. 设备注册与注销

  • **register_netdev()/unregister_netdev()**:注册/注销网络设备。
  • **alloc_etherdev()**:分配以太网设备(自动初始化常用字段)。

2. 中断管理

  • **request_irq()**:注册中断处理函数。
  • **free_irq()**:释放中断资源。
  • 示例
    static irqreturn_t mydriver_irq_handler(int irq, void *dev_id) {
        struct net_device *dev = dev_id;
        
        // 检查中断类型并处理
        if (mydriver_hw_irq_is_rx(dev)) {
            // 接收中断处理
            mydriver_rx(dev);
        } else if (mydriver_hw_irq_is_tx(dev)) {
            // 发送完成中断处理
            mydriver_tx_complete(dev);
        }
        
        return IRQ_HANDLED;
    }
    

五、高级特性接口

1. 多队列支持

  • **netdev_init_scheduler()**:初始化调度器,支持多队列。
  • **netdev_rx_queue_add()**:添加接收队列。

2. GRO(Generic Receive Offload)

  • 作用:将多个小包合并为一个大包,减少上层处理开销。
  • 接口:通过 napi_gro_receive()napi_gro_complete() 实现。

3. VLAN支持

  • **vlan_dev_add_vlan()/vlan_dev_remove_vlan()**:添加/删除VLAN设备。
  • **vlan_put_tag()/vlan_get_tag()**:操作VLAN标签。

六、调试与性能优化

1. 统计信息

  • **dev->stats**:维护设备统计信息(如接收/发送数据包数、错误数)。
  • 更新示例
    dev->stats.rx_packets++;
    dev->stats.rx_bytes += len;
    

2. 调试工具

  • **printk()**:内核日志输出。
  • **dev_dbg()/dev_err()**:设备特定的调试/错误日志。
  • **ethtool**:通过实现 ndo_ethtool_ops 支持用户空间调试工具。

总结

开发 Linux 网络驱动时,核心是理解 net_devicenet_device_opssk_buff 三者的关系,并正确实现发送和接收路径的关键回调函数。对于高性能场景,需重点关注 NAPI、多队列和 GRO 等优化机制。通过合理使用这些接口和数据结构,可构建出稳定、高效的网络驱动。

第一章 走进linux 1.1 GNU与Linux的成长 1.2 Linux的开发模式和运作机制 1.3走进Linux内核 1.4 分析Linux内核的意义 1.5 Linux内核结构 1.6 Linux内核源代码 1.7 Linux内核源代码分析工具 第二章 Linux运行的硬件基础 2.1 i386的寄存器 2.2 内存地址 2.3 段机制和描述符 2.4 分页机制 2.5 Linux中的分页机制 2.6 Linux中的汇编语言 第三章中断机制 3.1 中断基本知识 3.2中断描述符表的初始化 3.3异常处理 3.4 中断处理 3.5中断的后半部分处理机制 第四章 进程描述 4.1 进程和程序(Process and Program) 4.2 Linux中的进程概述 4.3 task_struct结构描述 4.4 task_struct结构在内存中的存放 4.5 进程组织的方式 4.6 内核线程 4.7 进程的权能 4.8 内核同步 第五章进程调度 5.1 Linux间系统 5.2 钟中断 5.3 Linux的调度程序-Schedule( ) 5.4 进程切换 第六章 Linux内存管理 6.1 Linux的内存管理概述 6.2 Linux内存管理的初始化 6.3 内存的分配和回收 6.4 地址映射机制 6.5 请页机制 6.6 交换机制 6.7 缓存和刷新机制 6.8 进程的创建和执行 第七章 进程间通信 7.1 管道 7.2 信号(signal) 7.3 System V 的IPC机制 第八章 虚拟文件系统 8.1 概述 8.2 VFS中的数据结构 8.3 高速缓存 8.4 文件系统的注册、安装与拆卸 8.5 限额机制 8.6 具体文件系统举例 8.7 文件系统的系统调用 8 .8 Linux2.4文件系统的移植问题 第九章 Ext2文件系统 9.1 基本概念 9.2 Ext2的磁盘布局和数据结构 9.3 文件的访问权限和安全 9.4 链接文件 9.5 分配策略 第十章 模块机制 10.1 概述 10.2 实现机制 10.3 模块的装入和卸载 10.4 内核版本 10.5 编写内核模块 第十一章 设备驱动程序 11.1 概述 11.2 设备驱动基础 11.3 块设备驱动程序 11.4 字符设备驱动程序 第十二章 网络 12.1 概述 12.2 网络协议 12.3 套接字(socket) 12.4 套接字缓冲区(sk_buff) 12.5 网络设备接口 第十三章 启动系统 13.1 初始化流程 13.2 初始化的任务 13.3 Linux 的Boot Loarder 13.4 进入操作系统 13.5 main.c中的初始化 13.6 建立init进程 附录: 1 Linux 2.4内核API 2.1 驱动程序的基本函数 2.2 双向循环链表的操作 2.3 基本C库函数 2.4 Linux内存管理中Slab缓冲区 2.5 Linux中的VFS 2.6 Linux的连网 2.7 网络设备支持 2.8 模块支持 2.9 硬件接口 2.10 块设备 2.11 USB 设备
本PDF电子书包含上下两册,共1576页,带目录,高清非扫描版本。 作者: 毛德操 胡希明 丛书名: Linux内核源代码情景分析 出版社:浙江大学出版社 目录 第1章 预备知识 1.1 Linux内核简介. 1.2 Intel X86 CPU系列的寻址方式 1.3 i386的页式内存管理机制 1.4 Linux内核源代码中的C语言代码 1.5 Linux内核源代码中的汇编语言代码 第2章 存储管理 2.1 Linux内存管理的基本框架 2.2 地址映射的全过程 2.3 几个重要的数据结构和函数 2.4 越界访问 2.5 用户堆栈的扩展 2.6 物理页面的使用和周转 2.7 物理页面的分配 2.8 页面的定期换出 2.9 页面的换入 2.10 内核缓冲区的管理 2.11 外部设备存储空间的地址映射 2.12 系统调用brk() 2.13 系统调用mmap() 第3章 中断、异常和系统调用 3.1 X86 CPU对中断的硬件支持 3.2 中断向量表IDT的初始化 3.3 中断请求队列的初始化 3.4 中断的响应和服务 3.5 软中断与Bottom Half 3.6 页面异常的进入和返回 3.7 钟中断 3.8 系统调用 3.9 系统调用号与跳转表 第4章 进程与进程调度 4.1 进程四要素 4.2 进程三部曲:创建、执行与消亡 4.3 系统调用fork()、vfork()与clone() 4.4 系统调用execve() 4.5 系统调用exit()与wait4() 4.6 进程的调度与切换 4.7 强制性调度 4.8 系统调用nanosleep()和pause() 4.9 内核中的互斥操作 第5章 文件系统 5.1 概述 5.2 从路径名到目标节点 5.3 访问权限与文件安全性 5.4 文件系统的安装和拆卸 5.5 文件的打开与关闭 5.6 文件的写与读 5.7 其他文件操作 5.8 特殊文件系统/proc 第6章 传统的Unix进程间通信 6.1 概述 6.2 管道和系统调用pipe() 6.3 命名管道 6.4 信号 6.5 系统调用ptrace()和进程跟踪 6.6 报文传递 6.7 共享内存 6.8 信号量 第7章基于socket的进程间通信 7.1系统调用socket() 7.2函数sys—socket()——创建插口 7.3函数sys—bind()——指定插口地址 7.4函数sys—listen()——设定server插口 7.5函数sys—accept()——接受连接请求 7.6函数sys—connect()——请求连接 7.7报文的接收与发送 7.8插口的关闭 7.9其他 第8章设备驱动 8.1概述 8.2系统调用mknod() 8.3可安装模块 8.4PCI总线 8.5块设备的驱动 8.6字符设备驱动概述 8.7终端设备与汉字信息处理 8.8控制台的驱动 8.9通用串行外部总线USB 8.10系统调用select()以及异步输入/输出 8.11设备文件系统devfs 第9章多处理器SMP系统结构 9.1概述 9.2SMP结构中的互斥问题 9.3高速缓存与内存的一致性 9.4SMP结构中的中断机制 9.5SMP结构中的进程调度 9.6SMP系统的引导 第10章系统引导和初始化 10.1系统引导过程概述 10.2系统初始化(第一阶段) 10.3系统初始化(第二阶段) 10.4系统初始化(第三阶段) 10.5系统的关闭和重引导

2,856

社区成员

发帖
与我相关
我的任务
社区描述
本论坛以AI、WoS 、XR、IoT、Auto、生成式AI等核心板块组成,为开发者提供便捷及高效的学习和交流平台。 高通开发者专区主页:https://qualcomm.csdn.net/
人工智能物联网机器学习 技术论坛(原bbs) 北京·东城区
社区管理员
  • csdnsqst0050
  • chipseeker
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧