网卡状态变更,virtio-net检测
实现方案:
现在在amp模式下linux端有个真实的物理网卡eth0,有一个虚拟网卡virtio-net0后端,此时需要一种机制,将真实物理网卡的状态发送rtos的virtio-net0前端。这里使用register_netdevice_notifier机制,每个virtio-net设备都有自己的notifier,支持多个virtio-net设备实例。
这个实现的特点:
- 每个virtio-net设备独立管理自己的notifier,支持多实例
- 正确处理网卡引用计数(dev_get_by_name/dev_put)
- 可以通过carrier_notify_enabled动态控制状态同步
- 在probe时同步初始状态
- 在remove时正确清理资源
注意:
- 使用字符串保存物理网卡名称,而不是直接保存指针,否则可能会出现物理网卡还未初始化的情况。
- 不管物理网卡是否就绪都会注册notifier
- 在notifier回调中,当检测到目标网卡时才获取其设备指针
- 避免了在probe时因找不到网卡而无法注册notifier的问题
这里详细讲讲register_netdevice_notifier通知链。register_netdevice_notifier 是 Linux 网络子系统中的一个通知链(Notification Chain)机制,它允许内核模块注册一个回调函数来监听网络设备状态的变化。主要用途如下:
- 通知链的基本概念:
struct notifier_block {int (*notifier_call)(struct notifier_block *, unsigned long, void *);struct notifier_block *next;int priority;
};
- 主要事件类型:
// 一些重要的网络设备事件
#define NETDEV_UP 0x0001 // 网卡启用
#define NETDEV_DOWN 0x0002 // 网卡禁用
#define NETDEV_REBOOT 0x0003 // 网卡重启
#define NETDEV_CHANGE 0x0004 // 网卡状态改变
#define NETDEV_REGISTER 0x0005 // 网卡注册
#define NETDEV_UNREGISTER 0x0006 // 网卡注销
#define NETDEV_CHANGEMTU 0x0007 // MTU改变
#define NETDEV_CHANGEADDR 0x0008 // MAC地址改变
- 注册流程:
// 1. 定义通知块
struct notifier_block netdev_notifier = {.notifier_call = virtnet_netdev_event, // 回调函数
};// 2. 注册通知
register_netdevice_notifier(&netdev_notifier);// 3. 实现回调函数
static int virtnet_netdev_event(struct notifier_block *this,unsigned long event, void *ptr)
{struct net_device *dev = netdev_notifier_info_to_dev(ptr);switch(event) {case NETDEV_UP:// 处理网卡启用事件break;case NETDEV_DOWN:// 处理网卡禁用事件break;// ...}return NOTIFY_DONE;
}
- 工作原理:
- 当网络设备状态发生变化时,内核会遍历所有注册的通知块
- 按照优先级顺序调用每个通知块的 notifier_call 回调函数
- 回调函数可以返回:
- NOTIFY_OK: 事件处理成功
- NOTIFY_DONE: 事件与该模块无关
- NOTIFY_BAD: 事件处理失败
- 在你的代码中的应用:
// 注册通知监听物理网卡状态
vi->netdev_notifier.notifier_call = virtnet_netdev_event;
vi->carrier_notify_enabled = true;err = register_netdevice_notifier(&vi->netdev_notifier);
if (err) {dev_err(&vdev->dev, "Failed to register netdev notifier\n");return err;
}
当物理网卡状态发生变化时:
- UP事件: 更新虚拟网卡状态为启用,并通知前端
- DOWN事件: 更新虚拟网卡状态为禁用,并通知前端
- CHANGE事件: 根据物理网卡carrier状态更新虚拟网卡
- 注销流程:
// 在驱动卸载时需要注销通知
unregister_netdevice_notifier(&vi->netdev_notifier);
这种通知机制的优点:
- 解耦合 - 模块间通过事件通知而不是直接调用
- 灵活性 - 可以动态注册/注销监听器
- 实时性 - 能及时获得网络设备状态变化
- 可扩展 - 支持多个模块同时监听同一事件
在你的虚拟网卡驱动中,这个机制用于同步物理网卡和虚拟网卡的状态,确保虚拟网卡能正确反映物理网卡的工作状态。
结构体:
struct virtnet_info {...char eth_name[IFNAMSIZ]; // 保存物理网卡名称struct net_device *eth_dev; // 物理网卡指针(动态获取)struct notifier_block netdev_notifier;bool carrier_notify_enabled;}
初始化:
static int virtnet_probe(struct virtio_device *vdev)
{/* 在netdev注册后初始化carrier notify */printk("------------>carrier notify init\r\n");// 设置要监控的物理网卡名称,最好是设备树中定义的网卡名称,先写定strncpy(vi->eth_name, "eth0", IFNAMSIZ-1);vi->eth_name[IFNAMSIZ-1] = '\0';vi->eth_dev = NULL; // 初始时设为NULL// 初始化并注册notifiervi->netdev_notifier.notifier_call = virtnet_netdev_event;// 设置notifier为启用状态,最好是设备树中定义的状态是否启用vi->carrier_notify_enabled = true;err = register_netdevice_notifier(&vi->netdev_notifier);if (err) {dev_err(&vdev->dev, "Failed to register netdev notifier\n");goto free_unregister_netdev;}
通知链中的触发处理函数:
static int virtnet_netdev_event(struct notifier_block *this,unsigned long event, void *ptr)
{struct net_device *dev = netdev_notifier_info_to_dev(ptr);struct virtnet_info *vi = container_of(this, struct virtnet_info, netdev_notifier);struct virtio_net_config *config;int cpu = 2;u16 status;// 检查参数有效性if (!dev || !vi || !vi->dev)return NOTIFY_DONE;// 只关心指定物理网卡的事件if (strcmp(dev->name, vi->eth_name) != 0)return NOTIFY_DONE;// 如果找到匹配的网卡,保存其指针if (!vi->eth_dev) {vi->eth_dev = dev;dev_hold(dev); // 增加引用计数printk("------------>Found target network device: %s\n", dev->name);}if (!vi->carrier_notify_enabled)return NOTIFY_DONE;// 获取共享内存中的配置区域指针config = (struct virtio_net_config *)vi->vdev->config_ptr;switch (event) {case NETDEV_UP:// 物理网卡up时,更新carrier状态和共享内存状态netif_carrier_on(vi->dev);status = VIRTIO_NET_S_LINK_UP | VIRTIO_NET_S_ANNOUNCE;config->status = cpu_to_virtio16(vi->vdev, status);virtio_irq_trigger(virtio_irq_controller_get_default(), vi->vdev->irq, cpu);break;case NETDEV_DOWN:// 物理网卡down时,更新carrier状态和共享内存状态netif_carrier_off(vi->dev);status = VIRTIO_NET_S_ANNOUNCE; // 只设置ANNOUNCE标志config->status = cpu_to_virtio16(vi->vdev, status);virtio_irq_trigger(virtio_irq_controller_get_default(), vi->vdev->irq, cpu);break;case NETDEV_CHANGE:......break;default:return NOTIFY_DONE;}return NOTIFY_OK;
}
相关文章:
网卡状态变更,virtio-net检测
实现方案: 现在在amp模式下linux端有个真实的物理网卡eth0,有一个虚拟网卡virtio-net0后端,此时需要一种机制,将真实物理网卡的状态发送rtos的virtio-net0前端。这里使用register_netdevice_notifier机制,每个virtio-n…...
中华人民共和国保守国家秘密法
中华人民共和国保守国家秘密法 (1988年9月5日第七届全国人民代表大会常务委员会第三次会议通过 2010年4月29日第十一届全国人民代表大会常务委员会第十四次会议第一次修订 2024年2月27日第十四届全国人民代表大会常务委员会第八次会议第二次修订) 目…...
ELK日志收集系统部署
1、 ElasticSearch部署 Elastic — 搜索 AI 公司 | Elastic 系统类型:Centos7.4 节点IP:172.16.246.234 软件版本:jdk-8u191-linux-x64.tar.gz、elasticsearch-6.5.4.tar.gz 示例节点:172.16.246.234 1、安装配置jdk8 ES运行依…...
3D线上艺术展:艺术与技术的完美融合
随着数字技术的飞速发展,未来的艺术展览正逐步迈向线上线下融合的新阶段。其中,3D线上展览以其独特的魅力,成为线下展览的延伸与拓展,为艺术爱好者们开辟了全新的观赏途径。 对于艺术家和策展人而言,3D线上展览不仅打…...
TiDB 的MPP架构概述
MPP架构介绍: 如图,TiDB Server 作为协调者,首先 TiDB Server 会把每个TiFlash 拥有的region 会在TiFlash上做交换,让表连接在一个TiFlash上。另外 TiFlash会作为计算节点,每个TiFlash都负责数据交换,表连接…...
Leetcode 10-正则表达式匹配/ 剑指 Offer 19. 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。 ‘.’ 匹配任意单个字符 ‘*’ 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s 的,而不是部分字符串。 题解 字符串匹配多…...
FFmpeg 编码和解码
文章目录 音频格式AACADIF音频数据交换格式ADTS音频数据传输流 音频解码音频编码 视频格式H264GOP图像组I帧,P帧,B帧H264压缩技术H264压缩级别H264视频级别H264码流结构SPSPPS 解码视频编码视频 音频格式 AAC AAC全称 Advanced Audio Coding࿰…...
kali当中web扫描工具的用法
1. cadaver 用途:用于与WebDAV服务器交互,可进行文件上传、下载、目录浏览等操作。使用方法 连接到WebDAV服务器:cadaver <WebDAV服务器地址>,例如cadaver https://example.com/dav,然后按提示输入用户名和密码…...
深度剖析 Android Animation 框架
深度剖析 Android Animation 框架 目录 引言Android Animation 框架概述架构设计 3.1 核心类与接口3.2 动画类型3.3 动画执行流程使用指南 4.1 属性动画4.2 视图动画4.3 过渡动画设计模式 5.1 策略模式5.2 观察者模式5.3 工厂模式核心逻辑 6.1 动画插值器6.2 动画估值器6.3 动…...
泰山派GPIO子系统驱动---亮灯
本人linux驱动小白,文章基于B站up主 李Sir______ 视频内容记录,做笔记用。如有错误欢迎指正。本文将以开发板第40引脚GPIO3_B4作为LED灯珠的控制引脚,高电平灯亮,低电平灯灭。 杂话 在linux内核中,芯片厂商已经把所有…...
【C#特性整理】C#特性及语法基础
1. C#特性 1.1 统一的类型系统 C#中, 所有类型都共享一个公共的基类型. 例如,任何类型的实例都可以通过调用ToString方法将自身转换为一个字符串 1.2 类和接口 接口: 用于将标准与实现隔离, 仅仅定义行为,不做实现. 1.3 属性、方法、事件 属性: 封装了一部分对…...
Presence:Colyseus用于管理实时分布式数据的工具
Colyseus Presence 详细介绍 Presence 是 Colyseus 中用于管理实时分布式数据的一种工具。它主要用于在多房间、多服务器或分布式部署中实现玩家的实时在线状态、数据共享和通信。Presence 提供了一套简单的 API 来处理诸如在线玩家跟踪、分布式数据存储和发布/订阅模式等功能…...
Ubuntu 搭建SVN服务
目录 1、安装SVN服务端 2、创建SVN版本库 3、修改SVN配置svnserve.conf 3.1 配置文件介绍 3.2 svnserve.conf配置 3.3 authz配置设置用户读写权限 3.4 passwd配置 用户名密码 4、启动SVN服务 4.1 配置开机启动 1、安装SVN服务端 sudo apt-get install subversion…...
HTML速查
HTML 基本文档 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>文档标题</title></head><body>可见文本...</body> </html>基本标签(Basic Tags) <h1>最大的…...
day-102 二进制矩阵中的最短路径
思路 BFS 解题过程 从起点依次向八个方向尝试(之后也一样),如果某个位置在矩阵内且值为0且没有访问过,将其添加到一个队列中,依次类推,直到到达出口 Code class Solution {public int shortestPathBinar…...
SQL Server大批量数据插入
数据库连接及相关操作 public class DataBase {/*** 驱动*/private static final String DRIVER PropertiesUtil.getString("spring.datasource.driver-class-name");/*** 数据库地址*/private static final String URL PropertiesUtil.getString("spring.da…...
在 Ubuntu 下通过 Docker 部署 Caddy 服务器
嘿,伙伴们!今天我们来聊聊如何在 Ubuntu 系统下通过 Docker 部署 Caddy 服务器。Caddy 是一个现代的 Web 服务器,支持自动 HTTPS,简单易用,特别适合快速搭建网站。而 Docker 则是一个让你可以隔离和管理应用的神器。结…...
ZooKeeper注册中心实现
具体步骤 安装ZooKeeper(启动端口占用,2181:客户端,8080:管理端)引入客户端依赖实现注册中心接口SPI补充ZooKeeper注册中心 引入依赖 <!-- zookeeper --> <dependency><groupId>org.a…...
数仓建模:如何进行实体建模?
目录 1 如何进行实体建模? 业务建模 领域建模 逻辑建模 2 实体建模具体步骤 需求分析...
Python编程技术
设计目的 该项目框架Scrapy可以让我们平时所学的技术整合旨在帮助学习者提高Python编程技能并熟悉基本概念: 1. 学习基本概念:介绍Python的基本概念,如变量、数据类型、条件语句、循环等。 2. 掌握基本编程技巧:教授学生如何使…...
图片格式转换效率革命:从繁琐流程到一键操作的技术突破
图片格式转换效率革命:从繁琐流程到一键操作的技术突破 【免费下载链接】Save-Image-as-Type Save Image as Type is an chrome extension which add Save as PNG / JPG / WebP to the context menu of image. 项目地址: https://gitcode.com/gh_mirrors/sa/Save-…...
智能匹配技术:重新定义Illustrator设计效率提升新范式
智能匹配技术:重新定义Illustrator设计效率提升新范式 【免费下载链接】illustrator-scripts Adobe Illustrator scripts 项目地址: https://gitcode.com/gh_mirrors/il/illustrator-scripts 一、行业困境分析:设计师如何摆脱机械劳动的桎梏&…...
CMake的project()命令,除了起名字还能干啥?一个例子讲透VERSION和DESCRIPTION的妙用
CMake的project()命令:从命名到项目管理的进阶实践 CMake作为现代C/C项目构建的事实标准,其project()命令往往是每个CMakeLists.txt文件的开篇之作。大多数开发者仅将其视为项目命名的工具,却忽略了它作为项目元数据中心枢纽的潜力。本文将深…...
【数据可视化实战】从API到图表:一步步构建奥运奖牌榜与运动员数据分析平台
1. 数据获取:从API到结构化数据 做数据分析的第一步永远是获取数据。这次我们选择奥运奖牌榜和运动员数据作为案例,主要是因为这类数据公开透明且结构清晰,非常适合新手练手。我实测下来,咪咕视频的奥运数据接口非常稳定…...
RFSOC XCZU47DR在5G射频基带开发中的实战应用(含代码示例)
RFSOC XCZU47DR在5G射频基带开发中的实战应用(含代码示例) 在5G通信系统的开发中,射频基带处理一直是工程师面临的核心挑战之一。Xilinx的RFSOC XCZU47DR凭借其独特的架构设计,将高性能RF数据转换器与可编程逻辑完美融合ÿ…...
MCP与CLI之争:AI Agent的协议之辩
MCP vs CLI:AI Agent 的协议之辩 2026年2月底到3月,AI 开发者社区爆发了一场关于 AI Agent 工具调用方式的激烈争论。一方说"MCP 已死,CLI 万岁",另一方说"MCP 没死,我们只是太早了"。而飞书、钉钉…...
Java虚拟线程在亿级订单系统中的生死切换(高并发架构避坑指南·仅限内部团队流出版)
第一章:Java 25虚拟线程在亿级订单系统中的定位与生死边界在单机承载日均超两亿订单的高并发场景下,传统平台线程模型(每请求一 OS 线程)已触及内核调度、内存开销与上下文切换的物理极限。Java 25 将虚拟线程(Virtual…...
FasterRCNN训练完别急着关!用predict.py批量预测并保存结果的完整配置指南
FasterRCNN模型预测实战:从批量推理到结果保存的全流程解析 当你终于完成FasterRCNN模型漫长的训练过程,看着损失曲线平稳下降,验证集指标达到预期,那种成就感不言而喻。但很多开发者在这里犯了一个常见错误——直接关闭项目转向下…...
哪款头戴式蓝牙耳机性价比高?十大热门平价头戴式耳机品牌推荐!
2026年头戴耳机市场新老品牌争奇斗艳,从入门到高端让人目不暇接。作为一名经历过选择困难的音频爱好者,我完全理解这种幸福的烦恼:参数术语堆砌、营销话术包装,让人难辨虚实。在实测过多款产品后,我发现关键要避开这些…...
Rust 时间处理神器:chrono 从入门到实战
Rust 时间处理神器:chrono 从入门到实战 在 Rust 生态中,chrono 凭借其遵循 ISO 8601 标准、支持时区、类型安全且性能优异的特性,成为了 Rust 开发者的首选工具。本文将从入门到进阶,并结合实际开发场景带你全面掌握 chrono 的使…...
