123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- // https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c
- use super::KObject;
- use super::KobjUeventEnv;
- use super::KobjectAction;
- use super::{UEVENT_BUFFER_SIZE, UEVENT_NUM_ENVP};
- use crate::driver::base::kobject::{KObjectManager, KObjectState};
- use crate::init::initcall::INITCALL_POSTCORE;
- use crate::libs::mutex::Mutex;
- use crate::libs::rwlock::RwLock;
- use crate::net::socket::netlink::af_netlink::netlink_has_listeners;
- use crate::net::socket::netlink::af_netlink::NetlinkSocket;
- use crate::net::socket::netlink::af_netlink::{netlink_broadcast, NetlinkSock};
- use crate::net::socket::netlink::skbuff::SkBuff;
- use crate::net::socket::netlink::{
- netlink_kernel_create, NetlinkKernelCfg, NETLINK_KOBJECT_UEVENT, NL_CFG_F_NONROOT_RECV,
- };
- use alloc::boxed::Box;
- use alloc::collections::LinkedList;
- use alloc::string::{String, ToString};
- use alloc::sync::Arc;
- use alloc::vec::Vec;
- use core::fmt::Write;
- use num::Zero;
- use system_error::SystemError;
- use unified_init::macros::unified_init;
- // 全局变量
- pub static UEVENT_SEQNUM: u64 = 0;
- // #ifdef CONFIG_UEVENT_HELPER
- // char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
- // #endif
- struct UeventSock {
- inner: NetlinkSock,
- }
- impl UeventSock {
- pub fn new(inner: NetlinkSock) -> Self {
- UeventSock { inner }
- }
- }
- // 用于存储所有用于发送 uevent 消息的 netlink sockets。这些 sockets 用于在内核和用户空间之间传递设备事件通知。
- // 每当需要发送 uevent 消息时,内核会遍历这个链表,并通过其中的每一个 socket 发送消息。
- // 使用 Mutex 保护全局链表
- lazy_static::lazy_static! {
- static ref UEVENT_SOCK_LIST: Mutex<LinkedList<UeventSock>> = Mutex::new(LinkedList::new());
- }
- // 回调函数,当接收到 uevent 消息时调用
- fn uevent_net_rcv() {
- // netlink_rcv_skb(skb, &uevent_net_rcv_skb);
- }
- /// 内核初始化的时候,在设备初始化之前执行
- #[unified_init(INITCALL_POSTCORE)]
- fn kobejct_uevent_init() -> Result<(), SystemError> {
- // todo: net namespace
- return uevent_net_init();
- }
- // TODO:等net namespace实现后添加 net 参数和相关操作
- // 内核启动的时候,即使没有进行网络命名空间的隔离也需要调用这个函数
- // 支持 net namespace 之后需要在每个 net namespace 初始化的时候调用这个函数
- /// 为每一个 net namespace 初始化 uevent
- fn uevent_net_init() -> Result<(), SystemError> {
- let cfg = NetlinkKernelCfg {
- groups: 1,
- flags: NL_CFG_F_NONROOT_RECV,
- ..Default::default()
- };
- // 创建一个内核 netlink socket
- let ue_sk = UeventSock::new(netlink_kernel_create(NETLINK_KOBJECT_UEVENT, Some(cfg)).unwrap());
- // todo: net namespace
- // net.uevent_sock = ue_sk;
- // 每个 net namespace 向链表中添加一个新的 uevent socket
- UEVENT_SOCK_LIST.lock().push_back(ue_sk);
- log::info!("uevent_net_init finish");
- return Ok(());
- }
- // 系统关闭时清理
- fn uevent_net_exit() {
- // 清理链表
- UEVENT_SOCK_LIST.lock().clear();
- }
- /// kobject_uevent,和kobject_uevent_env功能一样,只是没有指定任何的环境变量
- pub fn kobject_uevent(kobj: Arc<dyn KObject>, action: KobjectAction) -> Result<(), SystemError> {
- // kobject_uevent和kobject_uevent_env功能一样,只是没有指定任何的环境变量
- match kobject_uevent_env(kobj, action, Vec::new()) {
- Ok(_) => Ok(()),
- Err(e) => Err(e),
- }
- }
- /// kobject_uevent_env,以 envp 为环境变量,上报一个指定 action 的 uevent。环境变量的作用是为执行用户空间程序指定运行环境。
- pub fn kobject_uevent_env(
- kobj: Arc<dyn KObject>,
- action: KobjectAction,
- envp_ext: Vec<String>,
- ) -> Result<i32, SystemError> {
- log::info!("kobject_uevent_env: kobj: {:?}, action: {:?}", kobj, action);
- let mut state = KObjectState::empty();
- let mut top_kobj = kobj.parent().unwrap().upgrade().unwrap();
- let mut retval: i32;
- let action_string = match action {
- KobjectAction::KOBJADD => "add".to_string(),
- KobjectAction::KOBJREMOVE => "remove".to_string(),
- KobjectAction::KOBJCHANGE => "change".to_string(),
- KobjectAction::KOBJMOVE => "move".to_string(),
- KobjectAction::KOBJONLINE => "online".to_string(),
- KobjectAction::KOBJOFFLINE => "offline".to_string(),
- KobjectAction::KOBJBIND => "bind".to_string(),
- KobjectAction::KOBJUNBIND => "unbind".to_string(),
- };
- /*
- * Mark "remove" event done regardless of result, for some subsystems
- * do not want to re-trigger "remove" event via automatic cleanup.
- */
- if let KobjectAction::KOBJREMOVE = action {
- log::info!("kobject_uevent_env: action: remove");
- state.insert(KObjectState::REMOVE_UEVENT_SENT);
- }
- // 不断向上查找,直到找到最顶层的kobject
- while let Some(weak_parent) = top_kobj.parent() {
- log::info!("kobject_uevent_env: top_kobj: {:?}", top_kobj);
- top_kobj = weak_parent.upgrade().unwrap();
- }
- /* 查找当前kobject或其parent是否从属于某个kset;如果都不从属于某个kset,则返回错误。(说明一个kobject若没有加入kset,是不会上报uevent的) */
- if kobj.kset().is_none() && top_kobj.kset().is_none() {
- log::info!("attempted to send uevent without kset!\n");
- return Err(SystemError::EINVAL);
- }
- let kset = top_kobj.kset();
- // 判断该 kobject 的状态是否设置了uevent_suppress,如果设置了,则忽略所有的uevent上报并返回
- if kobj.kobj_state().contains(KObjectState::UEVENT_SUPPRESS) {
- log::info!("uevent_suppress caused the event to drop!");
- return Ok(0);
- }
- // 如果所属的kset的kset->filter返回的是0,过滤此次上报
- if let Some(kset_ref) = kset.as_ref() {
- if let Some(uevent_ops) = &kset_ref.uevent_ops {
- if uevent_ops.filter() == Some(0) {
- log::info!("filter caused the event to drop!");
- return Ok(0);
- }
- }
- }
- // 判断所属的kset是否有合法的名称(称作subsystem,和前期的内核版本有区别),否则不允许上报uevent
- // originating subsystem
- let subsystem: String = if let Some(kset_ref) = kset.as_ref() {
- if let Some(uevent_ops) = &kset_ref.uevent_ops {
- let name = uevent_ops.uevent_name();
- if !name.is_empty() {
- name
- } else {
- kobj.name()
- }
- } else {
- kobj.name()
- }
- } else {
- kobj.name()
- };
- if subsystem.is_empty() {
- log::info!("unset subsystem caused the event to drop!");
- }
- log::info!("kobject_uevent_env: subsystem: {}", subsystem);
- // 创建一个用于环境变量的缓冲区
- let mut env = Box::new(KobjUeventEnv {
- argv: Vec::with_capacity(UEVENT_NUM_ENVP),
- envp: Vec::with_capacity(UEVENT_NUM_ENVP),
- envp_idx: 0,
- buf: vec![0; UEVENT_BUFFER_SIZE],
- buflen: 0,
- });
- if env.buf.is_empty() {
- log::error!("kobject_uevent_env: failed to allocate buffer");
- return Err(SystemError::ENOMEM);
- }
- // 获取设备的完整对象路径
- let devpath: String = KObjectManager::kobject_get_path(&kobj);
- log::info!("kobject_uevent_env: devpath: {}", devpath);
- if devpath.is_empty() {
- retval = SystemError::ENOENT.to_posix_errno();
- // goto exit
- drop(devpath);
- drop(env);
- log::warn!("kobject_uevent_env: devpath is empty");
- return Ok(retval);
- }
- retval = add_uevent_var(&mut env, "ACTION=%s", &action_string).unwrap();
- log::info!("kobject_uevent_env: retval: {}", retval);
- if !retval.is_zero() {
- drop(devpath);
- drop(env);
- log::info!("add_uevent_var failed ACTION");
- return Ok(retval);
- };
- retval = add_uevent_var(&mut env, "DEVPATH=%s", &devpath).unwrap();
- if !retval.is_zero() {
- drop(devpath);
- drop(env);
- log::info!("add_uevent_var failed DEVPATH");
- return Ok(retval);
- };
- retval = add_uevent_var(&mut env, "SUBSYSTEM=%s", &subsystem).unwrap();
- if !retval.is_zero() {
- drop(devpath);
- drop(env);
- log::info!("add_uevent_var failed SUBSYSTEM");
- return Ok(retval);
- };
- /* keys passed in from the caller */
- for var in envp_ext {
- let retval = add_uevent_var(&mut env, "%s", &var).unwrap();
- if !retval.is_zero() {
- drop(devpath);
- drop(env);
- log::info!("add_uevent_var failed");
- return Ok(retval);
- }
- }
- if let Some(kset_ref) = kset.as_ref() {
- if let Some(uevent_ops) = kset_ref.uevent_ops.as_ref() {
- if uevent_ops.uevent(&env) != 0 {
- retval = uevent_ops.uevent(&env);
- if retval.is_zero() {
- log::info!("kset uevent caused the event to drop!");
- // goto exit
- drop(devpath);
- drop(env);
- return Ok(retval);
- }
- }
- }
- }
- match action {
- KobjectAction::KOBJADD => {
- state.insert(KObjectState::ADD_UEVENT_SENT);
- }
- KobjectAction::KOBJUNBIND => {
- zap_modalias_env(&mut env);
- }
- _ => {}
- }
- //mutex_lock(&uevent_sock_mutex);
- /* we will send an event, so request a new sequence number */
- retval = add_uevent_var(&mut env, "SEQNUM=%llu", &(UEVENT_SEQNUM + 1).to_string()).unwrap();
- if !retval.is_zero() {
- drop(devpath);
- drop(env);
- log::info!("add_uevent_var failed");
- return Ok(retval);
- }
- retval = kobject_uevent_net_broadcast(kobj, &env, &action_string, &devpath);
- // todo: 设置了 UEVENT_HELP 编译条件之后,使用 handle_uevent_helper() 对指定的 uevent 进行处理,通常是热插拔程序 mdev、udev 等
- drop(devpath);
- drop(env);
- log::info!("kobject_uevent_env: retval: {}", retval);
- return Ok(retval);
- }
- /// 以格式化字符的形式,将环境变量copy到env指针中。
- pub fn add_uevent_var(
- env: &mut Box<KobjUeventEnv>,
- format: &str,
- args: &str,
- ) -> Result<i32, SystemError> {
- log::info!("add_uevent_var: format: {}, args: {}", format, args);
- if env.envp_idx >= env.envp.capacity() {
- log::info!("add_uevent_var: too many keys");
- return Err(SystemError::ENOMEM);
- }
- let mut buffer = String::new();
- write!(&mut buffer, "{} {}", format, args).map_err(|_| SystemError::ENOMEM)?;
- let len = buffer.len();
- if len >= env.buf.capacity() - env.buflen {
- log::info!("add_uevent_var: buffer size too small");
- return Err(SystemError::ENOMEM);
- }
- // Convert the buffer to bytes and add to env.buf
- env.buf.extend_from_slice(buffer.as_bytes());
- env.buf.push(0); // Null-terminate the string
- env.buflen += len + 1;
- // Add the string to envp
- env.envp.push(buffer);
- env.envp_idx += 1;
- Ok(0)
- }
- // 用于处理设备树中与模块相关的环境变量
- fn zap_modalias_env(env: &mut Box<KobjUeventEnv>) {
- // 定义一个静态字符串
- const MODALIAS_PREFIX: &str = "MODALIAS=";
- let mut len: usize;
- let mut i = 0;
- while i < env.envp_idx {
- // 如果是以 MODALIAS= 开头的字符串
- if env.envp[i].starts_with(MODALIAS_PREFIX) {
- len = env.envp[i].len() + 1;
- // 如果不是最后一个元素
- if i != env.envp_idx - 1 {
- // 将后续的环境变量向前移动,以覆盖掉 "MODALIAS=" 前缀的环境变量
- for j in i..env.envp_idx - 1 {
- env.envp[j] = env.envp[j + 1].clone();
- }
- }
- // 减少环境变量数组的索引,因为一个变量已经被移除
- env.envp_idx -= 1;
- // 减少环境变量的总长度
- env.buflen -= len;
- } else {
- i += 1;
- }
- }
- }
- // 用于处理网络相关的uevent(通用事件)广播
- // https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c#381
- pub fn kobject_uevent_net_broadcast(
- kobj: Arc<dyn KObject>,
- env: &KobjUeventEnv,
- action_string: &str,
- devpath: &str,
- ) -> i32 {
- // TODO: net namespace
- // 如果有网络命名空间,则广播标记的uevent;如果没有,则广播未标记的uevent
- let ret = uevent_net_broadcast_untagged(env, action_string, devpath);
- log::info!("kobject_uevent_net_broadcast finish. ret: {}", ret);
- ret
- }
- /// 分配一个用于 uevent 消息的 skb(socket buffer)。
- pub fn alloc_uevent_skb<'a>(
- env: &'a KobjUeventEnv,
- action_string: &'a str,
- devpath: &'a str,
- ) -> Arc<RwLock<SkBuff>> {
- let skb = Arc::new(RwLock::new(SkBuff::new(None)));
- skb
- }
- // https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c#309
- /// 广播一个未标记的 uevent 消息
- pub fn uevent_net_broadcast_untagged(
- env: &KobjUeventEnv,
- action_string: &str,
- devpath: &str,
- ) -> i32 {
- log::info!(
- "uevent_net_broadcast_untagged: action_string: {}, devpath: {}",
- action_string,
- devpath
- );
- let mut retval = 0;
- let mut skb = Arc::new(RwLock::new(SkBuff::new(None)));
- // 锁定 UEVENT_SOCK_LIST 并遍历
- let ue_sk_list = UEVENT_SOCK_LIST.lock();
- for ue_sk in ue_sk_list.iter() {
- // 如果没有监听者,则跳过
- if netlink_has_listeners(&ue_sk.inner, 1) == 0 {
- log::info!("uevent_net_broadcast_untagged: no listeners");
- continue;
- }
- // 如果 skb 为空,则分配一个新的 skb
- if skb.read().inner.is_empty() {
- log::info!("uevent_net_broadcast_untagged: alloc_uevent_skb failed");
- retval = SystemError::ENOMEM.to_posix_errno();
- skb = alloc_uevent_skb(env, action_string, devpath);
- if skb.read().inner.is_empty() {
- continue;
- }
- }
- log::info!("next is netlink_broadcast");
- let netlink_socket = Arc::new(ue_sk.inner.clone());
- retval = match netlink_broadcast(&netlink_socket, Arc::clone(&skb), 0, 1, 1) {
- Ok(_) => 0,
- Err(err) => err.to_posix_errno(),
- };
- log::info!("finished netlink_broadcast");
- // ENOBUFS should be handled in userspace
- if retval == SystemError::ENOBUFS.to_posix_errno()
- || retval == SystemError::ESRCH.to_posix_errno()
- {
- retval = 0;
- }
- }
- // consume_skb(skb);
- retval
- }
|