【C语言】linux内核packet_setsockopt

一、中文注释
// 发送数据包函数。它尝试通过特定的网络设备队列直接传输一个skb(socket缓冲区)。
static int packet_direct_xmit(struct sk_buff *skb)
{return dev_direct_xmit(skb, packet_pick_tx_queue(skb)); // 调用dev_direct_xmit函数,并传入skb和通过packet_pick_tx_queue选择的发送队列。
}// 设置socket选项的函数。这个函数负责处理网络层的各种选项设置。
static int
packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
{struct sock *sk = sock->sk; // 从socket结构中获取sock结构。struct packet_sock *po = pkt_sk(sk); // 将sock结构转换为packet_sock结构体。int ret;if (level != SOL_PACKET)return -ENOPROTOOPT; // 如果层级不是SOL_PACKET,返回错误。// 根据选项名称执行相应的操作。switch (optname) {case PACKET_ADD_MEMBERSHIP:case PACKET_DROP_MEMBERSHIP:{struct packet_mreq_max mreq; // 定义多播请求结构。int len = optlen; // 获取选项长度。memset(&mreq, 0, sizeof(mreq)); // 初始化多播请求结构。if (len < sizeof(struct packet_mreq))return -EINVAL; // 如果传入的长度小于packet_mreq结构大小,返回无效参数错误。if (len > sizeof(mreq))len = sizeof(mreq); // 如果传入的长度大于packet_mreq_max结构大小,调整为packet_mreq_max结构大小。if (copy_from_user(&mreq, optval, len))return -EFAULT; // 从用户空间拷贝数据失败,则返回错误。if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address)))return -EINVAL; // 如果长度小于mreq结构中mr_address成员起始位置加上地址长度,则返回无效参数错误。if (optname == PACKET_ADD_MEMBERSHIP)ret = packet_mc_add(sk, &mreq); // 添加多播组成员。elseret = packet_mc_drop(sk, &mreq); // 删除多播组成员。return ret; // 返回操作结果。}case PACKET_RX_RING:case PACKET_TX_RING:{union tpacket_req_u req_u;int len;lock_sock(sk); // 锁定sock结构。switch (po->tp_version) {case TPACKET_V1:case TPACKET_V2:len = sizeof(req_u.req); // 设置请求结构大小。break;case TPACKET_V3:default:len = sizeof(req_u.req3); // 设置请求结构大小。break;}if (optlen < len) {ret = -EINVAL; // 如果传入长度小于请求结构大小,返回无效参数错误。} else {if (copy_from_user(&req_u.req, optval, len))ret = -EFAULT; // 从用户空间拷贝数据失败,则返回错误。elseret = packet_set_ring(sk, &req_u, 0, optname == PACKET_TX_RING); // 设置环形缓冲区。}release_sock(sk); // 释放sock结构锁。return ret; // 返回操作结果。}// 设置数据包复制阈值,当skb长度小于此值时复制数据。
case PACKET_COPY_THRESH:
{int val;if (optlen != sizeof(val))return -EINVAL; // 如果选项长度不合法,返回错误。if (copy_from_user(&val, optval, sizeof(val)))return -EFAULT; // 如果用户空间数据拷贝失败,返回错误。pkt_sk(sk)->copy_thresh = val; // 设置数据包复制阈值。return 0;
}
// ...
// 设置packet socket的版本号。
case PACKET_VERSION:
{int val;if (optlen != sizeof(val))return -EINVAL; // 如果选项长度不合法,返回错误。if (copy_from_user(&val, optval, sizeof(val)))return -EFAULT; // 如果用户空间数据拷贝失败,返回错误。switch (val) {case TPACKET_V1:case TPACKET_V2:case TPACKET_V3:break; // 如果为有效版本,继续执行。default:return -EINVAL; // 如果为无效版本,返回错误。}lock_sock(sk); // 锁定sock结构。if (po->rx_ring.pg_vec || po->tx_ring.pg_vec) {ret = -EBUSY; // 如果已经设置了环形缓冲区,则返回忙。} else {po->tp_version = val; // 设置协议版本。ret = 0;}release_sock(sk); // 释放sock结构锁。return ret; // 返回操作结果。
}
// ...
// 设置packet socket是否绕过队列规则处理。
case PACKET_QDISC_BYPASS:
{int val;if (optlen != sizeof(val))return -EINVAL; // 如果选项长度不合法,返回错误。if (copy_from_user(&val, optval, sizeof(val)))return -EFAULT; // 如果用户空间数据拷贝失败,返回错误。po->xmit = val ? packet_direct_xmit : dev_queue_xmit; // 根据val的值选择是直接传输还是进入队列规则处理。return 0;
}
// ...
// 默认case,如果没有匹配到任何选项,代表不支持该协议选项。
default:return -ENOPROTOOPT; // 返回不支持的协议选项错误。
// 所有case分支的目的都是处理socket层的不同选项设置,如添加/删除多播组,设置缓冲区大小和环形配置,调整性能选项等。
// 每个case分支以处理特定选项名(optname)为基础,对socket结构的特定成员进行赋值或执行相关操作函数。}
}
这段代码是Linux内核网络栈中的一部分,提供对原始套接字层的操作。`packet_direct_xmit` 函数用于直接通过指定的网络队列发送数据包。`packet_setsockopt` 函数是一个针对`SOL_PACKET`套接字层级的设置选项的函数,可以添加或删除多播组成员,设置缓冲区环区域,修改某些性能参数等。这些操作通常是由网络程序进行socket编程时所使用。
每个 case 分支处理一个特定的套接字选项,例如 PACKET_RX_RING 或 PACKET_TX_RING 用于分配或释放环形缓冲区,而 PACKET_COPY_THRESH 用于设置包拷贝阈值等。每个分支内部通常会首先验证用户提供的参数长度是否合法,然后从用户空间拷贝数据到内核空间,接着进行相应的设置修改,某些情况下还需要在操作前后获取和释放锁,以保护数据结构的一致性。如果选项设置成功,通常会返回 0,否则返回错误码。

二、中文讲解
第一个函数 packet_direct_xmit:
static int packet_direct_xmit(struct sk_buff *skb)
{return dev_direct_xmit(skb, packet_pick_tx_queue(skb));
}
packet_direct_xmit 函数是一个非常简单的函数,它接收一个 sk_buff 结构体指针 skb(代表网络数据包),调用 dev_direct_xmit 函数直接将这个数据包发送出去。发送的队列是由 packet_pick_tx_queue(skb) 函数返回的。通常这个函数被用作数据包的直接传输,规避了一些队列管理机制。
第二个函数 packet_setsockopt:
static int packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
{// ...
}
packet_setsockopt 函数用于设置给定套接字 sock 的某些选项。函数参数 level 表示选项的级别,这里必须是 SOL_PACKET,否则返回 -ENOPROTOOPT 错误。`optname` 指定了要设置的选项的名称,`optval` 是指向包含选项值的用户空间缓冲区的指针,而 optlen 表示缓冲区的长度。
函数体内是一个 switch 语句,根据 optname 的不同,执行不同的操作:
1. PACKET_ADD_MEMBERSHIP 和 PACKET_DROP_MEMBERSHIP:用于管理数据包多播成员资格。
2. PACKET_RX_RING 和 PACKET_TX_RING:设置接收和发送环形缓冲区,这些操作涉及到性能优化,以高效处理网络数据包。
3. PACKET_COPY_THRESH:设置数据包复制阈值。
4. PACKET_VERSION:指定环形缓冲区版本(TPACKET_V1, TPACKET_V2, 或 TPACKET_V3)。
5. PACKET_RESERVE:为环形缓冲区中每个帧预留空间。
6. PACKET_LOSS:设置丢包选项,以模拟网络丢包情况。
7. PACKET_AUXDATA:启用或禁用附加数据。
8. PACKET_ORIGDEV:路由过程中获取原始设备信息的选项。
9. PACKET_VNET_HDR:用于虚拟网络设备头部的选项。
10. PACKET_TIMESTAMP:设置数据包的时间戳类型。
11. PACKET_FANOUT 和 PACKET_FANOUT_DATA:用于将数据包分发到多个程序。
12. PACKET_TX_HAS_OFF:设置是否启用硬件校验和。
13. PACKET_QDISC_BYPASS:设置是否绕过队列规则直接发送数据包。
对于每种情况,在设置选项前都有一些校验逻辑来保证输入参数的有效性。如果输入参数无效,函数会返回相应的错误代码(例如 -EINVAL 表示无效参数)。各种选项设置可能涉及到从用户空间复制数据到内核空间(使用 copy_from_user),也可能对套接字状态加锁来确保线程安全。成功执行操作后,函数通常返回 0 表示成功。

相关文章:
【C语言】linux内核packet_setsockopt
一、中文注释 // 发送数据包函数。它尝试通过特定的网络设备队列直接传输一个skb(socket缓冲区)。 static int packet_direct_xmit(struct sk_buff *skb) {return dev_direct_xmit(skb, packet_pick_tx_queue(skb)); // 调用dev_direct_xmit函数&#x…...
LeetCode的使用方法
LeetCode的使用方法 一、LeetCode是什么?1.LeetCode简介2.LeetCode官网 二、LeetCode的使用方法1.注册账号2.力扣社区力扣编辑器 2.1 讨论发起讨论参与讨论关注讨论 2.2 文章撰写文章关注文章 3.力扣面试官版测评面试招聘竞赛 4.力扣学习LeetBook 书架我的阅读猜您喜…...
Vue事件处理:.passive修饰符与应用场景
.passive修饰符 passive这个修饰符会执行默认方法。你们可能会问,明明默认执行为什么会设置这样一个修饰符。这就要说一下这个修饰符的本意了。 浏览器只有等内核线程执行到事件监听器对应的JavaScript代码时,才能知道内部是否会调用preventDefa…...
智慧城市中的数字孪生:构建城市管理的未来框架
目录 一、引言 二、数字孪生技术概述 三、数字孪生技术在智慧城市中的应用 1、实时监测与预警 2、模拟与优化 3、智能化决策 4、协同与共享 四、数字孪生技术构建城市管理的未来框架的价值 1、提高管理效率 2、优化资源配置 3、提升公共服务水平 4、增强应对突发事…...
强引用、软引用、弱引用、幻象引用 —— Java的四种引用类型解析
强引用、软引用、弱引用、幻象引用 —— Java的四种引用类型解析 在Java中,对象的生命周期并不总是由我们直接控制。除了我们常见的强引用外,Java还提供了软引用、弱引用和幻象引用这三种引用类型,它们对对象生命周期的影响各不相同。理解这…...
基于禁忌搜索算法(TS)的TSP(Python实现)
本篇文章是博主在最化优学习、人工智能等领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在最优化算…...
Linux shell 网络掩码地址转CIDR
例子: ./1.sh 255.255.255.0 ./1.sh 255.255.255.128 ./1.sh 255.255.0.0 源实现: #!/bin/bashnetmask_to_cidr() {local IFSlocal -a octetslocal i0local cidr0IFS. read -r -a octets <<< "$1"for octet in "${octets[]}…...
C#,煎饼排序问题(Pancake Sorting Problem)算法与源代码
1 煎饼排序问题 给定一个未排序的数组,任务是对给定数组进行排序。您只能在阵列上执行以下操作。 翻转(arr,i):将数组从0反转为i 示例: 输入:arr[]{23、10、20、11、12、6、7} 输出:…...
13.西瓜书——半监督学习
1.概述 (1) 纯半监督学习 (Pure Semi-Supervised Learning) 纯半监督学习是一种典型的半监督学习方法,它的主要特点是同时利用有标签数据和无标签数据进行模型训练。目标是通过整合这两种类型的数据来提高模型的泛化性能。在这个过程中&#…...
C++进阶之路---继承(二)
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、继承与友元 友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。 class Student; class Per…...
C及C++每日练习(3)
选择题: 1.以下程序的输出结果是() #include <stdio.h> main() { char a[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, *p; int i; i 8; p a i; printf("%s\n", p - 3); } A.6 B. 6789 C. 6 D.789 对于本题࿰…...
黑马点评-附近商户实现
GEO数据结构 Redis在3.2版本中加入了对GEO的支持,允许存储地理坐标信息,根据经纬度来检索数据。 GEO本质上是基于sortedSet实现的,在Sorted Set中,每个成员都是与一个分数(score)相关联的,这个分数用于对成员进行排序…...
安装nginx:手动安装和yum安装
本文在centos7.9下分别尝试了yum安装和手动安装,记录一下试验过程。为后来者少踩点坑。 下载 下载地址:链接 。建议下载稳定版本,也就是Stable Version,这里下载的是 nginx-1.24.0 # 我下载在如下文件夹 mkdir/opt/apps cd /op…...
【C++ STL详解】——string类
目录 前言 一、string类对象的常见构造 二、string类对象的访问及遍历 1.下标【】(底层operator【】函数) 编辑 2.迭代器 3.范围for 4.at 5.back和front 三、string类对象的容量操作 1.size 和 length 2.capacity 3.empty 4.clear 5.res…...
MatplotlibPython 1 3.7
放大数据,如果想仔细看某一行的数据的时候 可以调不同的颜色,图片的长宽高,以及线的种类 plt.figure 这个命令下的所有东西都在这个figure里面 plt.xlim 改变坐标轴的范围 plt.xlabel 改变坐标轴的总名称 plt.xticks 换单位 plt.yt…...
深入理解 Dubbo:构建分布式服务治理体系
目录 1. 介绍 2. Dubbo 的核心概念 2.1 服务提供者(Provider)与服务消费者(Consumer) 2.2 注册中心(Registry) 2.3 监控中心(Monitor) 3. Dubbo 的功能特性 3.1 远程调用&…...
唤起原生IOS和安卓Android app的方法
大家好我是咕噜美乐蒂,很高兴又和大家见面了! 要唤起原生 iOS 或 Android 应用程序,你可以使用以下方法: 唤起原生 iOS 应用程序 在 iOS 上,你可以使用自定义 URL 方案或 Universal Links 来唤起原生应用程序。以下…...
RabbitMQ的web控制端介绍
2.1 web管理界面介绍 connections:无论生产者还是消费者,都需要与RabbitMQ建立连接后才可以完成消息的生产和消费,在这里可以查看连接情况channels:通道,建立连接后,会形成通道,消息的投递、获取…...
GitHub登不上:修改hosts文件来解决(GitHub520,window)
参考链接:GitHub520: 本项目无需安装任何程序,通过修改本地 hosts 文件,试图解决: GitHub 访问速度慢的问题 GitHub 项目中的图片显示不出的问题 花 5 分钟时间,让你"爱"上 GitHub。 (gitee.com) GitHub网站…...
01-DevOps代码上线-git入门及gitlab远程仓库
一、准备学习环境 10.0.0.71-gitlab 2c2g-20GB 10.0.0.72-jenkins 2c2g-20GB 10.0.0.73-sonarqube 1c1g-20GB 10.0.0.74-nexus 1c1g-20GB 10.0.0.75-dm 1c1g-20GB (模拟写代码服务器) 在centos系统中&…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
6.9-QT模拟计算器
源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...
