进程与进程,进程与内核间通信(netlink)

来源:互联网 发布:江西师大网络教学平台 编辑:程序博客网 时间:2024/05/16 07:17

进程与进程间通信方式IPC:

1. 早期unix IPC:管道,FIFO,信号

2. System V IPC(贝尔实验室): system V消息队列,system V信号灯,system V共享内存

3. socket IPC (BSD)

4. Posix IPC: Posix消息队列,Posix信号灯,Posix共享内存


线程间通信:

1. 全局变量

2. 线程锁

3. pthread_time_wait


进程与内核间通信

1. ioctl()

2. 共享内存:mmap()

3. netlink

4. 其他

其他: 内核启动参数;模块参数;sysfs;procfs;debugfs;relayfs;sysctl;系统调用;copy_from_user()/copy_to_user();get_user()/put_user();信号/信号量/管道等等


netlink可以实现

1. 内核向进程广播(如热插拔事件)

2. 进程与内核双向通信

3. 进程与进程通信。


参考:

《Linux内核设计与实现》(Linux Kernel Development)第3版 》
Linux 用户态与内核态的交互——netlink 篇:http://bbs.chinaunix.net/thread-2162796-1-1.html
《Linux 系统内核空间与用户空间通信的实现与分析》 陈鑫 http://www-128.ibm.com/developerworks/cn/linux/l-netlink/?ca=dwcn-newsletter-linux
《在 Linux 下用户空间与内核空间数据交换的方式》 杨燚 http://www-128.ibm.com/developerworks/cn/linux/l-kerns-usrs/
http://blog.csdn.net/wangpengqi/article/details/9969599

上: http://blog.chinaunix.net/uid-23069658-id-3400761.html

中: http://blog.chinaunix.net/uid-23069658-id-3405954.html 

下: http://blog.chinaunix.net/uid-23069658-id-3409786.html


3.10的内核比2.6的内核,netlink接口函数发生了一些变化。

// 内核态netlink_kernel_create()netlink_unicast()netlink_broadcast()// 用户态socket()bind()sendmsg()recvmsg()close()




进程A和子系统1之间是单播通信,进程B、C和子系统2是多播通信。上图还向我们说明了一个信息。从用户空间传递到内核的数据是不需要排队的,即其操作是同步完成;而从内核空间向用户空间传递数据时需要排队,是异步的。


Netlink消息由两部分组成:消息头和有效数据载荷,且整个Netlink消息是4字节对齐。消息头为固定的16字节,消息体长度可变,采用TLV(Type-Length-Value)格式






// Kernel#define NETLINK_ATC_SUSPEND 30#define PM_NETLINK_GROUP 1#define PM_NETLINK_SUSPEND_KEY "gpio_suspend"#define ENTER_SUSPEND_GPIO 1 // GPIO1static struct sock *netlink_sock = NULL;static int netlink_broadcast(char *msg){    struct sk_buff *skb;    struct nlmsghdr *nlh;    int len = strlen(msg)+1;    printk(KERN_INFO "[%s %d] msg=[%s]\n", __FUNCTION__, __LINE__, msg);    if(!msg || !netlink_sock){        return -1;    }    skb = nlmsg_new(len, GFP_KERNEL);    if(!skb){        printk(KERN_ERR "[%s %d] \n", __FUNCTION__, __LINE__);        return -1;    }    nlh = nlmsg_put(skb, 0, 0, 0, len, 0);    NETLINK_CB(skb).portid = 0;    NETLINK_CB(skb).dst_group = PM_NETLINK_GROUP;    memcpy(NLMSG_DATA(nlh), msg, len);        printk(KERN_ERR "[%s %d] netlink broadcast msg [%s]\n", __FUNCTION__, __LINE__, msg);    return netlink_broadcast(netlink_sock, skb, 0, PM_NETLINK_GROUP, GFP_KERNEL);}static irqreturn_t suspend_gpio_irq_handler(int irq, void *data){    struct gpio_desc *desc = (struct gpio_desc *)data;    int gpio = desc_to_gpio(desc);    char msg[64];    int ret = 0;    snprintf(msg, sizeof(msg), "%s%d", PM_NETLINK_SUSPEND_KEY, gpio);    ret = atc_netlink_broadcast(msg);    return IRQ_HANDLED;}static int suspend_gpio_request_irq(void){    int gpio = ENTER_SUSPEND_GPIO;    struct gpio_desc *desc = gpio_to_desc(gpio);    int irq = gpiod_to_irq(desc);    if(irq > 0 && gpio_is_valid(gpio)){        #if 0        if(!gpio_suspend_workqueue) {            gpio_suspend_workqueue = create_singlethread_workqueue("gpio_wakeup");            INIT_WORK(&atc_gpio_suspend_work, atc_gpio_suspend_work_func);        }        #else        if(!netlink_sock){            struct netlink_kernel_cfg cfg = {                .input = NULL,            };            extern struct net init_net;            netlink_sock = netlink_kernel_create(&init_net, NETLINK_ATC_SUSPEND, &cfg);            if(!netlink_sock){                  printk(KERN_ERR "[ATC %s %d] netlink_kernel_create fail\n", __FUNCTION__, __LINE__);                return -1;              }        }        #endif        gpio_direction_input(gpio);        irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);        /* Regester IRQ */        if(request_irq(irq, suspend_gpio_irq_handler, IRQF_SHARED,                        PM_NETLINK_SUSPEND_KEY, desc)        ) {            printk(KERN_ERR "[%s %d] request_irq fail %d\n", __FUNCTION__, __LINE__, irq);        }    }    else{        printk(KERN_ERR "[%s %d] irq(%d) or gpio is not valid\n", __FUNCTION__, __LINE__, irq);    }    return 0;}// Userstatic void *pm_thread (void *arg){    struct sockaddr_nl src_addr;    struct nlmsghdr *nlh = NULL;    struct iovec iov;    struct msghdr msg;    int sock_fd, retval;    int fd_count = 0;    fd_set rfds, efds;    sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_SUSPEND);    if(sock_fd < 0){        goto exit;    }    memset(&src_addr, 0, sizeof(src_addr));    src_addr.nl_family = PF_NETLINK;    src_addr.nl_pid = 0;     src_addr.nl_groups = 1 << (PM_NETLINK_GROUP - 1);    retval = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));    if (retval < 0) {        goto exit;    }    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(PM_NETLINK_PAYLOAD_MAX));    if (!nlh) {        printf("malloc nlmsghdr %d-%s", errno, strerror(errno));        goto exit;    }    memset(nlh, 0, NLMSG_SPACE(PM_NETLINK_PAYLOAD_MAX));    iov.iov_base = (void *)nlh;    iov.iov_len = NLMSG_SPACE(PM_NETLINK_PAYLOAD_MAX);    memset(&msg, 0, sizeof(msg));    msg.msg_iov = &iov;    msg.msg_iovlen = 1;    FD_ZERO(&rfds);    FD_ZERO(&efds);    fd_count = sock_fd;    while (!pm_thread_quit) {        FD_SET(sock_fd, &rfds);        FD_SET(sock_fd, &efds);        retval = select(fd_count + 1, &rfds, NULL, &efds, NULL);        if (retval < 0) {            goto exit;        } else if (retval == 0) {        } else if (FD_ISSET(sock_fd, &rfds)){            if (recvmsg(sock_fd, &msg, 0) > 0) {                const char *s = (char*)NLMSG_DATA(nlh);                int len = strlen(PM_NETLINK_SUSPEND_KEY);                if(!strncmp(s, PM_NETLINK_SUSPEND_KEY, len)) {                    int pin = atoi(s+len);                    usleep(100000);                    if(gpio_get_value(pin) == 1) {                        printf("state");                    }                }            }        }    }exit:    if(sock_fd > 0)        close(sock_fd);    pm_thread_id = 0;    return NULL;} 


net_link.c----------------------------------------------------------------------#include <linux/kernel.h>#include <linux/module.h>#include <linux/types.h>#include <linux/sched.h>#include <net/sock.h>#include <net/netlink.h>#define NETLINK_TEST 21struct sock *nl_sk = NULL;EXPORT_SYMBOL_GPL(nl_sk);void nl_data_ready (struct sk_buff *__skb){  struct sk_buff *skb;  struct nlmsghdr *nlh;  u32 pid;  int rc;  int len = NLMSG_SPACE(1200);  char str[100];  printk("net_link: data is ready to read.\n");  skb = skb_get(__skb);  if (skb->len >= NLMSG_SPACE(0)) {    nlh = nlmsg_hdr(skb);    printk("net_link: recv %s.\n", (char *)NLMSG_DATA(nlh));    memcpy(str,NLMSG_DATA(nlh), sizeof(str));     pid = nlh->nlmsg_pid; /*pid of sending process */    printk("net_link: pid is %d\n", pid);    kfree_skb(skb);    skb = alloc_skb(len, GFP_ATOMIC);    if (!skb){      printk(KERN_ERR "net_link: allocate failed.\n");      return;    }    nlh = nlmsg_put(skb,0,0,0,1200,0);    NETLINK_CB(skb).pid = 0; /* from kernel */    memcpy(NLMSG_DATA(nlh), str, sizeof(str));    printk("net_link: going to send.\n");    rc = netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);    if (rc < 0) {      printk(KERN_ERR "net_link: can not unicast skb (%d)\n", rc);    }    printk("net_link: send is ok.\n");  }  return;}static int test_netlink(void) {  nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0, nl_data_ready, NULL, THIS_MODULE);  if (!nl_sk) {    printk(KERN_ERR "net_link: Cannot create netlink socket.\n");    return -EIO;  }  printk("net_link: create socket ok.\n");  return 0;}int init_module(){  test_netlink();  return 0;}void cleanup_module( ){  if (nl_sk != NULL){    sock_release(nl_sk->sk_socket);  }  printk("net_link: remove ok.\n");}MODULE_LICENSE("GPL");MODULE_AUTHOR("kidoln");----------------------------------------------------------------------sender.c----------------------------------------------------------------------#include <sys/stat.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/types.h>#include <string.h>#include <asm/types.h>#include <linux/netlink.h>#include <linux/socket.h>#define MAX_PAYLOAD 1024 /* maximum payload size*/struct sockaddr_nl src_addr, dest_addr;struct nlmsghdr *nlh = NULL;struct iovec iov;int sock_fd;struct msghdr msg;int main(int argc, char* argv[]){        sock_fd = socket(PF_NETLINK, SOCK_RAW, 21);        memset(&msg, 0, sizeof(msg));        memset(&src_addr, 0, sizeof(src_addr));        src_addr.nl_family = AF_NETLINK;        src_addr.nl_pid = getpid(); /* self pid */        src_addr.nl_groups = 0; /* not in mcast groups */        bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));        memset(&dest_addr, 0, sizeof(dest_addr));        dest_addr.nl_family = AF_NETLINK;        dest_addr.nl_pid = 0; /* For Linux Kernel */        dest_addr.nl_groups = 0; /* unicast */        nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));        /* Fill the netlink message header */        nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);        nlh->nlmsg_pid = getpid(); /* self pid */        nlh->nlmsg_flags = 0;        /* Fill in the netlink message payload */        strcpy(NLMSG_DATA(nlh), "Hello you!");        iov.iov_base = (void *)nlh;        iov.iov_len = nlh->nlmsg_len;        msg.msg_name = (void *)&dest_addr;        msg.msg_namelen = sizeof(dest_addr);        msg.msg_iov = &iov;        msg.msg_iovlen = 1;        printf(" Sending message. ...\n");        sendmsg(sock_fd, &msg, 0);        /* Read message from kernel */        memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));        printf(" Waiting message. ...\n");        recvmsg(sock_fd, &msg, 0);        printf(" Received message payload: %s\n",NLMSG_DATA(nlh));         /* Close Netlink Socket */        close(sock_fd);}----------------------------------------------------------------------Makefile----------------------------------------------------------------------MODULE_NAME :=net_linkobj-m :=$(MODULE_NAME).oKERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)all:    $(MAKE) -C $(KERNELDIR) M=$(PWD)    gcc -o sender sender.cclean:    rm -fr *.ko *.o *.cmd sender $(MODULE_NAME).mod.c----------------------------------------------------------------------



0 0
原创粉丝点击