最近应用需求需要实现一下硬盘、U盘、eSata备份的热插拔功能,内核对热插拔都以实现,但是怎么才能让应用层也能实时的知道有热插拔事件产生呢,刚开始想到的是用信号来实现异步通知,虽然已经实现,但是这种方法不太适用,不能将所有的热插拔事件统一起来,后来网上google了几篇关于netlink的文章,顺便做了下笔记。
Netlink提供了一种异步通讯方式,使用时与标准的socket API一样。
内核代码:
#include <linux/module.h> #include <linux/types.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/netlink.h> #include <linux/net.h> #include <net/sock.h> #include <linux/delay.h>
#define NETLINK_EXAMPLE 20 #define PAYLOAD 1024
static struct sock *sk = NULL;
static int netlink_example_init(void) { struct sk_buff *skb; char *str = "access kernel"; char *tmp; int len;
sk = netlink_kernel_create(NETLINK_EXAMPLE,1,NULL,NULL,THIS_MODULE);
if(IS_ERR(sk)){ printk("netlink kernel create failde\n"); return -ENOMEM; } //这里必须先调用netlink_kernel_create函数,将NETLINK_EXAMPLE注册到内核,否则调用bind会失败
msleep(10000);
len = strlen(str) + 1;
skb = alloc_skb(len,GFP_KERNEL);
if(skb){ tmp = skb_put(skb,len); sprintf(tmp,"%s",str); NETLINK_CB(skb).dst_group = 1; netlink_broadcast(sk,skb,0,1,GFP_KERNEL); } return 0; }
static void netlink_example_exit(void) { if(sk) sock_release(sk->sk_socket); }
MODULE_LICENSE("GPL");
module_init(netlink_example_init); module_exit(netlink_example_exit)
|
应用代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <sys/un.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <linux/types.h> #include <linux/netlink.h> #include <errno.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h>
#define NETLINK_EXAMPLE 20
static int init_sock() { int size = 1024; int ret; struct sockaddr_nl snl; memset((void *)snl,0,sizeof(struct sockaddr_nl)); snl.nl_family = AF_NETLINK; snl.nl_pid = getpid(); snl.nl_groups = 1;
int fd = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_EXAMPLE);//NETLINK_KOBJECT_UEVENT);
if (fd == -1) { perror("socket"); return -1; } ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); if(ret < 0){ perror("setsockopt"); close(fd); return -1; } ret = bind(fd, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl)); if (ret < 0) { perror("bind"); close(fd); return -1; }
return fd; }
int main(int argc, char* argv[]) { int fd = init_sock(); char buf[100] = {0}; printf("wait for kernel message\n"); recv(fd, &buf, sizeof(buf), 0); printf("=====%s\n",buf); return 0; }
|
先加载.ko文件,在运行应用代码,结果如下
# insmod /home/drive/netlink.ko & # /home/app/netlink & # wait for kernel message =====access kernel
|
内核对于热插拔的实现就是基于这种方式来实现异步通知应用层的,具体代码见/lib/kobject_uevent.c。
参考文章:
http://www.ibm.com/developerworks/cn/linux/l-netlink/index.html
阅读(2393) | 评论(0) | 转发(0) |