Chinaunix首页 | 论坛 | 博客
  • 博客访问: 226445
  • 博文数量: 42
  • 博客积分: 2618
  • 博客等级: 少校
  • 技术积分: 385
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-26 10:04
文章分类

全部博文(42)

文章存档

2013年(2)

2012年(2)

2011年(3)

2010年(17)

2009年(18)

我的朋友

分类: LINUX

2010-02-09 11:40:56

    最近应用需求需要实现一下硬盘、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) |
给主人留下些什么吧!~~