1、什么是NetLink?

它 是一种特殊的 socket,它是 Linux 所特有的,由于传送的消息是暂存在socket接收缓存中,并不被接收者立即处理,所以netlink是一种异步通信机制。 系统调用和 ioctl 则是同步通信机制。Netlink是面向数据包的服务,为内核与用户层搭建了一个高速通道。

用户空间进程可以通过标准socket API来实现消息的发送、接收。进程间通信的方式有:管道(Pipe)及命名管道(Named Pipe),信号(Signal),消息队列(Message queue),共享内存(Shared Memory),信号量(Semaphore),套接字(Socket)。

为了完成内核空间用户空间通信,Linux提供了基于socket的Netlink通信机制,可以实现内核与用户空间数据的及时交换。

2、在Linux3.0的内核版本中定义了下面的21个用于Netlink通信的宏

在include/linux/netlink.h文件中定义:

#define NETLINK_ROUTE        0    /* Routing/device hook                */
#define NETLINK_UNUSED        1    /* Unused number                */
#define NETLINK_USERSOCK    2    /* Reserved for user mode socket protocols     */
#define NETLINK_FIREWALL    3    /* Firewalling hook                */
#define NETLINK_INET_DIAG    4    /* INET socket monitoring            */
#define NETLINK_NFLOG        5    /* netfilter/iptables ULOG */
#define NETLINK_XFRM        6    /* ipsec */
#define NETLINK_SELINUX        7    /* SELinux event notifications */
#define NETLINK_ISCSI        8    /* Open-iSCSI */
#define NETLINK_AUDIT        9    /* auditing */
#define NETLINK_FIB_LOOKUP    10
#define NETLINK_CONNECTOR    11
#define NETLINK_NETFILTER    12    /* netfilter subsystem */
#define NETLINK_IP6_FW        13
#define NETLINK_DNRTMSG        14    /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT    15    /* Kernel messages to userspace */
#define NETLINK_GENERIC        16
/* leave room for NETLINK_DM (DM Events) */
#define NETLINK_SCSITRANSPORT    18    /* SCSI Transports */
#define NETLINK_ECRYPTFS    19
#define NETLINK_RDMA        20#define MAX_LINKS 32

3、建立Netlink会话过程如下:

(1)首先通过netlink_kernel_create()创建套接字,该函数的原型如下:

struct sock *netlink_kernel_create(struct net *net,  int unit,unsigned int groups,  void (*input)(struct sk_buff *skb),  struct mutex *cb_mutex,  struct module *module);

其中net参数是网络设备命名空间指针,input函数是netlink socket在接受到消息时调用的回调函数指针,module默认为THIS_MODULE.

(2)用户空间进程使用标准Socket API来创建套接字,将进程ID发送至内核空间,用户空间创建使用socket()创建套接字,该函数的原型如下:

int socket(int domain, int type, int protocol);

其中domain值为PF_NETLINK,即Netlink使用协议族。protocol为Netlink提供的协议或者是用户自定义的协议,Netlink提供的协议包括NETLINK_ROUTE, NETLINK_FIREWALL, NETLINK_ARPD, NETLINK_ROUTE6和 NETLINK_IP6_FW。

(3)接着使用bind函数绑定。Netlink的bind()函数把一个本地socket地址(源socket地址)与一个打开的socket进行关联。完成绑定,内核空间接收到用户进程ID之后便可以进行通讯。

(4)用户空间进程发送数据使用标准socket API中sendmsg()函数完成,使用时需添加struct msghdr消息和nlmsghdr消息头。一个netlink消息体由nlmsghdr和消息的payload部分组成,输入消息后,内核会进入nlmsghdr指向的缓冲区。

4、实例:热插拔监听

内核中使用uevent事件通知用户空间,uevent首先在内核中调用netlink_kernel_create()函数创建一个socket套接字,该函数原型在netlink.h有定义,其类型是表示往用户空间发送消息的NETLINK_KOBJECT_UEVENT,groups=1,由于uevent只往用户空间发送消息而不接受,因此其输入回调函数input和cb_mutex都设置为NULL。

当有事件发生的时候,调用 kobject_uevent()函数,实际上最终是调用
 netlink_broadcast_filtered(uevent_sock, skb , 0, 1, GFP_KERNEL , kobj_bcast_filter, kobj);完成广播任务。
  用户空间程序只需要创建一个socket描述符,将描述符绑定到接收地址,就可以实现热拔插事件的监听了。

    #include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <sys/types.h>#include <asm/types.h>//该头文件需要放在netlink.h前面防止编译出现__kernel_sa_family未定义#include <sys/socket.h>  #include <linux/netlink.h>void MonitorNetlinkUevent(){int sockfd;struct sockaddr_nl sa;int len;char buf[4096];struct iovec iov;struct msghdr msg;int i;memset(&sa,0,sizeof(sa));sa.nl_family=AF_NETLINK;sa.nl_groups=NETLINK_KOBJECT_UEVENT;sa.nl_pid = 0;//getpid(); both is okmemset(&msg,0,sizeof(msg));iov.iov_base=(void *)buf;iov.iov_len=sizeof(buf);msg.msg_name=(void *)&sa;msg.msg_namelen=sizeof(sa);msg.msg_iov=&iov;msg.msg_iovlen=1;sockfd=socket(AF_NETLINK,SOCK_RAW,NETLINK_KOBJECT_UEVENT);if(sockfd==-1)printf("socket creating failed:%s\n",strerror(errno));if(bind(sockfd,(struct sockaddr *)&sa,sizeof(sa))==-1)printf("bind error:%s\n",strerror(errno));len=recvmsg(sockfd,&msg,0);if(len<0)printf("receive error\n");else if(len<32||len>sizeof(buf))printf("invalid message");for(i=0;i<len;i++)if(*(buf+i)=='\0')buf[i]='\n';printf("received %d bytes\n%s\n",len,buf);close(sockfd);}int main(int argc,char **argv){printf("***********************start***********************\n");MonitorNetlinkUevent();printf("***********************ends************************\n");return 0;}

我们Cmake编译好程序,在设备上执行:开始从设备上拔掉SD卡,之后运行程序,再插入SD卡,如下结果是拔插事件。

创建socket描述符的时候指定协议族为AF_NETLINK或者PF_NETLINK,套接字type选择SOCK_RAW或者SOCK_DGRAM,Netlink协议并不区分这两种类型,第三个参数协议填充NETLINK_KOBJECT_UEVENT表示接收内核uevent信息。

接着就绑定该文件描述符到sockadd_nl,注意该结构体nl_groups是接收掩码,取~0是将接收所有来自内核的消息,我们接收热拔插只需要填NETLINK_KOBJECT_UEVENT即可。接下来调用recvmsg开始接收内核消息,recvmsg函数需要我们填充message报头,包括指定接收缓存等工作。该函数会阻塞直到有热拔插事件产生。因此根据实际的运用来实现自己的代码。

****************************************************************************************************************************************

****************************************************************************************************************************************

Notice:补充内容

当初的demo只是验证这种实现机制是正确的,但是在具体的实际应用中,我们的程序从一开始启动创建一个线程,去接收每一次监控的结果,我发现每一次插拔,会有很多种消息,比如SD卡插入,还有块信息(一次操作一共4个消息),SD卡拔出,同样的情况,;

//日志信息
count = 1
received 204 bytes
add@/devices/platform/jzmmc_v1.2.0/mmc_host/mmc0/mmc0:0001
ACTION=add
DEVPATH=/devices/platform/jzmmc_v1.2.0/mmc_host/mmc0/mmc0:0001
SUBSYSTEM=mmc          //SD卡
MMC_TYPE=SD
MMC_NAME=00000
MODALIAS=mmc:block
SEQNUM=521count = 2
received 102 bytes
add@/devices/virtual/bdi/179:0
ACTION=add
DEVPATH=/devices/virtual/bdi/179:0
SUBSYSTEM=bdi
SEQNUM=522count = 3
received 244 bytes
add@/devices/platform/jzmmc_v1.2.0/mmc_host/mmc0/mmc0:0001/block/mmcblk0
ACTION=add
DEVPATH=/devices/platform/jzmmc_v1.2.0/mmc_host/mmc0/mmc0:0001/block/mmcblk0
SUBSYSTEM=block                     //块
MAJOR=179
MINOR=0
DEVNAME=mmcblk0
DEVTYPE=disk
NPARTS=1
SEQNUM=523count = 4
received 270 bytes
add@/devices/platform/jzmmc_v1.2.0/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p1
ACTION=add
DEVPATH=/devices/platform/jzmmc_v1.2.0/mmc_host/mmc0/mmc0:0001/block/mmcblk0/mmcblk0p1
SUBSYSTEM=block
MAJOR=179
MINOR=1
DEVNAME=mmcblk0p1
DEVTYPE=partition
PARTN=1
SEQNUM=524

因此我们需要详细解析接收到的信息!!!,recvmsg函数会阻塞,因此代码要注意!!!!


/*
线程里处理的事情,创建socket,绑定,销毁socket等都在创建线程、关闭线程时实现,
*/while ((kSocketfd >= 0 )&&(kThreadisRunning >=0))  //{MessageLength = recvmsg(kSocketfd, &message, 0);if (MessageLength > 0 ){            /*4 : pesae message*/for(int i=0;i<MessageLength;i++){if(MeaasgeBuffer[i]=='\0') MeaasgeBuffer[i]='\n';}MeaasgeBuffer[MessageLength]='\0';ParsingMessages(MeaasgeBuffer, MessageLength);   //解析消息}else if (MessageLength < 0){printf("receive error!\n");}else if (MessageLength<32 || MessageLength>sizeof(MeaasgeBuffer)){printf("invalid message !");}}}

Linux中Netlink实现热插拔监控——内核与用户空间通信相关推荐

  1. linux 高效的文件系统事件监控 内核级解析方案 inotify

    转载 http://www.lvtao.net/config/inotify.html linux 高效的文件系统事件监控 内核级解析方案 inotify 安装inotify-tools (http: ...

  2. Linux中mod相关的命令 内核模块化 mod相关命令都是用来动态加载内核模块/驱动程序模块...

    Linux中mod相关的命令 内核模块化   mod相关命令都是用来动态加载内核模块/驱动程序模块 http://baike.baidu.com/link?url=lxiKxFvYm-UfJIxMjz ...

  3. linux kernel and user space通信机制,Linux内核与用户空间通信机制研究.pdf

    ISSN 1009-3044 E-mail:info@CCCC.net.CR ComputerKnowledgeandTechnology电脑知识与技术 http://www.dnzs.net.cn ...

  4. Linux内核和用户空间通信的方法

    Linux内核和用户空间通信的方法(二)- 使用netlink   作者:Kendo 2006-9-3 这是一篇学习笔记,主要是对<Linux 系统内核空间与用户空间通信的实现与分析>中的 ...

  5. linux一条命令添加用户并设置密码,linux中如何通过命令行来添加用户并设置密码...

    linux中如何通过命令行来添加用户并设置密码 (7页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.90 积分 LINUX中如何通过命令行来添加用户 ...

  6. linux重命名用户名_如何在Linux中更改或重命名用户名和用户ID?

    linux重命名用户名 The problem is we want to change the already created user name or user id. As we know th ...

  7. linux 内核与用户空间通信之netlink使用方法

    Linux中的进程间通信机制源自于Unix平台上的进程通信机制.Unix的两大分支AT&T Unix和BSD Unix在进程通信实现机制上的各有所不同,前者形成了运行在单个计算机上的Syste ...

  8. linux中匿名用户怎么登陆_南京课工场IT培训:Linux中vsftpd服务配置(匿名,用户,虚拟用户)...

    vsftpd概述 vsftpd 是"very secure FTP daemon"的缩写,安全性是它的一个最大的特点.vsftpd 是一个 UNIX 类操作系统上运行的服务器的名字 ...

  9. linux下usb的热插拔监控,怎么linux下检测 usb摄像头热插拔事件

    在linux下所有设备都是文件.所以对摄像头的操作其实就是对文件的操作.USB摄像头的设备文件就是在/dev目录下的video0(假如只有一个摄像头).在linux下操作摄像头就是使用v4l2对摄像头 ...

最新文章

  1. 通知中心NSNotificationCenter的使用
  2. matlab二维矩阵可视化几种方法
  3. 微信浏览器取消缓存的方法
  4. linux四种集群是什么,lvs四种集群特点及使用场景
  5. 饿了么4年+阿里2年:研发路上的一些总结与思考
  6. Windows 10环境下如何安装CMake?(更新时间:2021.9.13)
  7. Dollar toolbox 学习笔记(一)
  8. 《中国人工智能学会通讯》——12.44 分类型数据的定义
  9. 3个查看远端端口是否畅通的方法
  10. 标签树状结构JSP中树状图的代码实现
  11. windows java opencv怎么玩
  12. 音视频开发入门基础及视频会议即时通讯开源技术选择
  13. 字节跳动Java大数据工程师面试题、笔试题(含答案)
  14. 基于高德导航的Android大作业
  15. Vscode中报错 CommandNotFoundError: Your shell has not been properly configured to use 'conda activate'.
  16. vnc连接,什么是vnc连接?有好用的vnc连接软件推荐吗?
  17. C#中向Chart中添加数据
  18. 视频教程-OpenGL入门2019版-其他
  19. Spring依赖注入之p、c命名空间
  20. 移动端UI设计规范参考

热门文章

  1. 谷歌发布Amber项目,用AI分析脑电波诊断治疗抑郁症
  2. PotPlayer降噪处理和人声增强
  3. 基于Cri-dockerd使用Kubeadm部署Kubernetes1.25集群
  4. Android 日期选择器 DatePickerDialog 修改主题颜色
  5. Dell win10无法识别耳机还是扬声器/声音小喇叭上有红叉
  6. 小米笔记本AIR3触控板使用技巧
  7. 制造企业如何开展客户满意度调查?民安智库为你解答
  8. OJ 1220 勒让德多项式的值
  9. Problem C. L04-03 n阶勒让德多项式的值(递归)---初学简单版
  10. “无法定位程序输入点nextafterf于动态链接库MSVCR120_CLR0400.dll上“完美解决方案!