Netlink套接字
netlink套接字
Netlink套接字是专门用于用户控件与内核之间的通讯,尤其是监听uevent事件(热插拔,模块加载等);
socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
AF_NETLINK:Netlink协议族
SOCK_DGRAM:数据报模式(尽管 Netlink 是可靠的);
SOCK_CLOEXEC:设置 close-on-exec 标志,防止套接字被 exec() 继承。
NETLINK_KOBJECT_UEVENT:指定 Netlink 子协议,用于接收内核发出的 uevent 事件(如设备插拔)。
sockaddr_nl结构体
#include <linux/netlink.h>struct sockaddr_nl {sa_family_t nl_family; // 地址族,固定为 AF_NETLINKunsigned short nl_pad; // 填充字段,通常为 0pid_t nl_pid; // 进程的唯一标识(通常是进程 PID 或 0)__u32 nl_groups; // 多播组掩码(订阅的组别)
};
nl_family:地址族,必须设为 AF_NETLINK,表示 Netlink 通信。
nl_pad:保留字段,初始化为0
nl_pid:端口ID
用户空间:通常设为进程 PID(用于单播通信)。
内核:固定为 0。
nl_groups:多播组源码
0:仅接收单播消息
非零:订阅指定的多播组
uevent
Linux 系统中的一种事件通知机制,用于向用户空间发送有关内核和设备状态变化的通知。通常用于设备驱动程序、热插拔事件以及设备状态变化等场景,以便用户空间应用程序能够在这些事件发生时做出相应的响应。
代码示例
int fd = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
if (fd < 0) {perror("socket");exit(1);
}
struct sockaddr_nl addr = {.nl_family = AF_NETLINK,.nl_pid = getpid(), // 当前进程 PID 作为地址.nl_groups = 1, // 订阅内核广播组
};
bind(fd, (struct sockaddr*)&addr, sizeof(addr));
char buf[4096];
while (1) {ssize_t len = recv(fd, buf, sizeof(buf), 0);if (len > 0) {parse_uevent(buf, len); // 解析 uevent 消息}
}
uevent消息
uevent消息是 key=value 形式的字符串序列,以 \0 分隔,末尾双 \0。以mmc为例:
#方便观看
remove@/devices/soc0/soc/1f282600.sstar_sdmmc0/mmc_host/mmc0/mmc0:b369\0
ACTION=remove\0
DEVPATH=/devices/soc0/soc/1f282600.sstar_sdmmc0/mmc_host/mmc0/mmc0:b369\0
SUBSYSTEM=mmc\0
MMC_TYPE=SD\0
MMC_NAME=SDABC\0
MODALIAS=mmc:block\0
SEQNUM=446\0\0
#实际字符串
remove@/devices/soc0/soc/1f282600.sstar_sdmmc0/mmc_host/mmc0/mmc0:b369\0ACTION=remove\0DEVPATH=/devices/soc0/soc/1f282600.sstar_sdmmc0/mmc_host/mmc0/mmc0:b369\0SUBSYSTEM=mmc\0MMC_TYPE=SD\0MMC_NAME=SDABC\0MODALIAS=mmc:block\0SEQNUM=446\0\0
几个关键的key
ACTION:事件类型
DEVPATH:设备在内核中的路径(对应 /sys 下的路径)
SUBSYSTEM:子系统
DEVNAME:设备节点名
MAJOR:主设备号
MINOR:次设备号
SEQNUM:事件序列号(用于去重)
ACTION
用于描述设备或模块的状态变化,核心值如下:
add:新设备或者模块被添加到内核中;例如:插入sd卡,插入usb设备,加载驱动等
remove:设备或者模块从内核中移除;例如:拔出sd卡,拔出usb设备,卸载驱动等
change:设备或者模块的状态发生变化;例如:sd卡格式化
move:设备路径变更;例如:设备重命名,重新挂载其他路径
bind:设备与驱动绑定成功;例如:插入sd卡,并且sd卡被识别
unbind:设备与驱动解绑;例如:拔出sd卡
online:设备变为可用状态;
offline:设备变为不可用状态;
SUBSYSTEM
表示事件所属的内核子系统,用于分类设备或模块的类型。
block:块设备;例如:磁盘分区等
mmc:MMC/SD 卡设备
usb:usb设备;例如:主机控制器、存储设备、HID设备等
net:网络设备;例如:网卡、虚拟接口
pci:pci设备;例如:显卡,网卡
sound:音频设备;例如:麦克,声卡
tty:串行终端设备;例如串口
power_supply:电源设备;例如:电池,适配器
注意:不同的子系统也会有自己独有的key;例如:SUBSYSTEM=mmc; 会有MMC_TYPE;MMC_NAME等专属属性
SEQNUM
用于标识事件的唯一性和顺序。是一个单调递增的数值,从1 开始递增,直到溢出后循环;由内核在生成 uevent 时分配。因此每个事件的SEQNUM值是唯一的。
有时候内核可能某个事件发送多次;可以判断这个值,丢弃重复的即可;所以该值具有去重的功能。