网站的首页标题在哪里设置的,自己做的网站360显示过期,菏泽建筑模板厂家,怎样做网站制作实现方案#xff1a; 现在在amp模式下linux端有个真实的物理网卡eth0#xff0c;有一个虚拟网卡virtio-net0后端#xff0c;此时需要一种机制#xff0c;将真实物理网卡的状态发送rtos的virtio-net0前端。这里使用register_netdevice_notifier机制#xff0c;每个virtio-n…实现方案 现在在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;
}