【C语言】linux内核dev_direct_xmit

2024-03-01 11:20
文章标签 语言 linux 内核 dev direct xmit

本文主要是介绍【C语言】linux内核dev_direct_xmit,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、中文注释

这段代码是一个网络设备的直接数据包传输函数,在Linux内核网络子系统中用于处理数据包发送。函数签名 int dev_direct_xmit(struct sk_buff *skb, u16 queue_id) 表明这个函数用于发送指向 skb(socket buffer)结构的数据包,并使用指定的队列 queue_id。下面注释逐行解释这个函数的作用:

int dev_direct_xmit(struct sk_buff *skb, u16 queue_id)
{// 根据skb中存储的指向net_device结构的指针取得网络设备结构体struct net_device *dev = skb->dev;struct sk_buff *orig_skb = skb; // 保留原始的skb,用于后续对比struct netdev_queue *txq; // 指向网络设备发送队列的指针int ret = NETDEV_TX_BUSY; // 初始返回值设为忙bool again = false; // 用于标志是否需要再次尝试发送// 若网络设备没有激活或者网络连接不可用,则跳转到drop标签处理if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev)))goto drop;// 检查和处理发送数据包,如果需要可以进行分片;// again变量会在必要时被置为true以再次尝试发送skb = validate_xmit_skb_list(skb, dev, &again);if (skb != orig_skb) // 如果skb被改变,说明有问题,需要释放资源goto drop;// 设置skb的队列映射到指定的queue_idskb_set_queue_mapping(skb, queue_id);// 根据skb获取对应的发送队列txq = skb_get_tx_queue(dev, skb);local_bh_disable(); // 禁止本地软中断,用于保护代码段不被中断// 锁定硬件发送队列HARD_TX_LOCK(dev, txq, smp_processor_id());// 如果发送队列没有冻结或者没有停止,则调用netdev_start_xmit来进行发送if (!netif_xmit_frozen_or_drv_stopped(txq))ret = netdev_start_xmit(skb, dev, txq, false);// 解锁硬件发送队列HARD_TX_UNLOCK(dev, txq);local_bh_enable(); // 启用本地软中断// 如果发送不完整,则释放skb资源if (!dev_xmit_complete(ret))kfree_skb(skb);return ret; // 返回发送结果drop: // 标签:用于处理发送失败情况// 对设备发送失败计数增加atomic_long_inc(&dev->tx_dropped);// 释放skb链表资源kfree_skb_list(skb);return NET_XMIT_DROP; // 返回发送丢弃结果
}
EXPORT_SYMBOL(dev_direct_xmit); // 导出符号,使得在模块中可以使用这个函数

这个函数的作用是尝试将数据包通过指定的网络设备发送出去。首先会对设备的运行状态进行检查,然后对skb列表进行可递验证,在保证硬件发送队列未冻结或未停止的条件下,尝试通过`netdev_start_xmit`发送数据包。发送完成之后,还需要释放或处理skb资源。如果在过程中检查到网络设备不处于工作状态或skb出现异常,则会释放skb并递增发送失败计数。

二、中文讲解

dev_direct_xmit 函数是 Linux 网络子系统中负责将 socket buffer(或称作 sk_buff,是内核中表示网络数据包的结构)直接发送到指定的网络队列的函数。在讲解函数的具体实现前,需要了解 sk_buff 和其他一些网络相关的结构体。
以下是该函数的详解:
1. 初始化变量:函数接收两个参数,`skb`(要发送的数据包)以及 queue_id(要发送到的队列 ID)。此外,它定义了一些局部变量如网络设备(`dev`),原始 skb(`orig_skb`),网络队列(`txq`),函数返回值(`ret`,初始值设为 NETDEV_TX_BUSY 标志忙碌)以及一个标志变量 again。
2. 检查网络设备状态:通过 unlikely 宏,该函数检测网络设备 (dev) 是否正在运行(`netif_running`)以及网络链路(网络载波)是否正常(`netif_carrier_ok`)。如果任何条件不满足,就跳转到标签 drop。
3. 验证和处理数据包:通过调用 validate_xmit_skb_list 函数验证 skb 是否可发送,并处理可能的问题。如果处理后的 skb 不等于原始 skb,表示数据包在处理中被更改或发生错误,也要跳转到 drop。
4. 设置队列映射和获取队列:通过 skb_set_queue_mapping 设置 skb 的队列映射到指定的 queue_id,然后通过 skb_get_tx_queue 获取相应 txq(网络设备中的发送队列)。
5. 禁用本地底半处理(softirq):`local_bh_disable` 函数调用用于防止在处理发送过程中被其他底半部打断,如网络软件中断处理程序。
6. 锁定发送队列:使用 HARD_TX_LOCK 宏锁定发送队列以保证在多核或多线程的情况下发送的同步性。
7. 发送数据包:先检查发送队列没有被冻结(`netif_xmit_frozen_or_drv_stopped`),接着调用 netdev_start_xmit 函数来开始发送数据包。如果发送成功或等待发送,`ret` 会被设置为相应的状态。
8. 解锁发送队列和启用本地底半处理:完成发送操作后,使用 HARD_TX_UNLOCK 宏解锁发送队列,然后调用 local_bh_enable 重新启用本地底半处理。
9. 处理发送返回状态:如果 dev_xmit_complete 函数显示发送未完成(通常是因为发生了错误),则使用 kfree_skb 释放 skb。
10. 处理失败和释放资源:如果发生需要丢弃数据包的情况(`drop` 标签下执行的代码),函数通过原子操作(`atomic_long_inc`)增加网络设备统计中丢弃的数据包计数,然后释放 skb 列表,并返回 NET_XMIT_DROP 表示数据包已丢弃。
11. 导出符号:最后,`EXPORT_SYMBOL` 宏允许其他模块使用 dev_direct_xmit 函数。

dev_direct_xmit 函数通常用于绕过标准的发送流程,直接将数据包(`sk_buff`)加入到指定网络设备的发送队列。这是一个比较低层的函数,直接与网络设备驱动交互。它经常用于性能敏感或需要细粒度控制发送过程的场景。函数会做适当的状态检查,如检查网络设备是否启动并且链路是否正常,验证和预处理数据包,设置队列映射,获取发送队列,并尝试发送数据包。在发送过程中,`dev_direct_xmit` 会处理排队、设备锁定和统计更新等事项。

在 dev_direct_xmit 函数中,发送的数据,即 skb (socket buffer),通常是已经经过封装的 IP 数据包。`skb` 结构是内核中用来存储网络数据包的通用数据结构,它可以包含各种层次的网络协议数据,包括链路层(例如以太网帧)、网络层(如 IP)、传输层(如 TCP/UDP)以及上层的应用数据。
在数据发送流程中,当一个 IP 数据包准备被发送出去时,它会首先被封装成一个 sk_buff,并含有完整的协议信息,例如:
- IP 头(如源地址、目标地址、协议类型等)
- 可能的传输层头(如 TCP 或 UDP 头部)
- 应用层负载(真正的数据内容)
在数据包通过 dev_direct_xmit 函数发送之前,它可能已经通过了多个网络层次的处理,包括路由决策、网络地址转换(NAT)、排队规则等。如果是以太网设备,`skb` 也很可能已包含了以太网帧头部,这样网络设备驱动就可以将其直接放送到硬件发送队列以交由网络接口卡(NIC)发送出去。
因此,通过 dev_direct_xmit 发送的 skb 一般情况下是一个完整的已封装好的数据包,包括 IP 层及可能的其他层次。然而,确切的协议层次和封装细节取决于 skb 是如何在发送路径上被构造和处理的。

这篇关于【C语言】linux内核dev_direct_xmit的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/762294

相关文章

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

v0.dev快速开发

探索v0.dev:次世代开发者之利器 今之技艺日新月异,开发者之工具亦随之进步不辍。v0.dev者,新兴之开发者利器也,迅速引起众多开发者之瞩目。本文将引汝探究v0.dev之基本功能与优势,助汝速速上手,提升开发之效率。 何谓v0.dev? v0.dev者,现代化之开发者工具也,旨在简化并加速软件开发之过程。其集多种功能于一体,助开发者高效编写、测试及部署代码。无论汝为前端开发者、后端开发者