Kernel与用户进程通信

  测试IPv6 ready logo   rfc 3315的时候,遇到一个问题,要求在收到ICMPv6 RA的时候,DHCPv6  Client要发Solicit消息。在平常的应用中,都是启动DHCPv6  Client后,client每隔一段时间就会发送Solicit,而并不是要在收到RA的时候发送。于是就修改了下kernel和client的代码,使得在kernel收到RA消息时,发送消息给DHCPv6  Client,使client发送Solicit。

思路为:使用netlink_kernel_create建立消息机制。在DHCPv6 Client初始化的时候,新建类型为NETLINK_RTK_ICMP6_RA  的netlink socket,监听kernel的消息,并且把自己的pid发送给kernel, kernel 收到消息后,存储pid为全局变量。当kernel收到RA包后,将发送消息给pid的用户进程。用户进程收到消息,发送solicit。

Kernel中接收ICMPv6 RA的代码在linux-3.10/net/ipv6/ndisc.c。

Kernel:

  1. 初始化IPC

在ndisc_init()中加上进程通信的socket。

//create netlink socket

struct netlink_kernel_cfg cfg = {

.input    = nl_icmp_input,

};

printk("%s: before netlink_kernel_create\n", __func__);

icmp6_ra_sock = netlink_kernel_create(&init_net, NETLINK_RTK_ICMP6_RA, &cfg);

if (icmp6_ra_sock == NULL) {

printk(KERN_ERR "Netlink[Kernel] Cannot create netlink socket for ipv6 ra.\n");

return -EAFNOSUPPORT;

}

printk("Netlink[Kernel] create netlink socket for ipv6 ra ok.\n");

其中NETLINK_RTK_ICMP6_RA  为在netlink.h中定义的一个类型。nl_icmp_input用于接收用户层发来的信息。

2. 接收DHCPv6 Client发来的pid 信息

static void nl_icmp_input(struct sk_buff  *__skb)

{

struct sk_buff *skb;

struct nlmsghdr *nlh;

char str[100];

struct completion cmpl;

int i=10;

skb = skb_get (__skb);

if(skb->len >= NLMSG_SPACE(0))

{

nlh = nlmsg_hdr(skb);

memcpy(str, NLMSG_DATA(nlh), sizeof(str));

printk("Message received:%s\n",str) ;

DHCP6C_PID = nlh->nlmsg_pid;

printk("DHCP PID = %d:%s\n", DHCP6C_PID) ;

kfree_skb(skb);

}

return;

}

3. 收到RA后,发消息给用户进程

在ndisc_router_discovery中,确认RA包ok后,发送消息。

if (icmp6_ra_sock) {

printk("%s: ra socket is not null\n", __func__);

payloadLen = NLMSG_SPACE(payloadLen);

/*Alloc skb ,this check helps to call the fucntion from interrupt context */

if(in_atomic())

{

skb_ra = alloc_skb(payloadLen, GFP_ATOMIC);

}

else

{

skb_ra = alloc_skb(payloadLen, GFP_KERNEL);

}

if(!skb_ra)

{

printk(KERN_ERR "failed to alloc skb in %s",__FUNCTION__);

return;

}

nl_msgHdr = (struct nlmsghdr *)skb_ra->data;

nl_msgHdr->nlmsg_type = MESSAGE_ICMP6_RA;

nl_msgHdr->nlmsg_pid=0;/*from kernel */

nl_msgHdr->nlmsg_len = payloadLen;

nl_msgHdr->nlmsg_flags =0;

NETLINK_CB(skb_ra).portid = 0; /*from kernel */

skb_ra->len = payloadLen;

err = netlink_unicast(icmp6_ra_sock, skb_ra, DHCP6C_PID, MSG_DONTWAIT); //send to dhcp6c

if (err < 0)

printk("%s: nfnetlink_unicast icmpv6 ra socket fail\n", __func__);

else

printk("%s: nfnetlink_unicast icmpv6 ra socket ok\n", __func__);

}

用户层:

  1. Dhcp6c 初始化,并发送pid给kernel

int init_ra_monitor_fd()

{

int ret = 0;

struct sockaddr_nl src_addr, dest_addr;

struct nlmsghdr *nlh = NULL;

struct iovec iov;

struct msghdr msg;

int state_smg = 0;

int pid = getpid();

if ((rasock = socket(AF_NETLINK, SOCK_RAW, NETLINK_RTK_ICMP6_RA)) < 0)

{

printf("Could not open netlink socket for kernel monitor\n");

return 1;

}

else

{

printf("kernelMonitorFd=%d\n", rasock);

}

memset(&src_addr, 0, sizeof(src_addr));

src_addr.nl_family = AF_NETLINK;

src_addr.nl_pid = pid;

src_addr.nl_groups = 0; // multicast

if (bind(rasock, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0)

{

printf("Could not bind netlink socket for kernel monitor\n");

close(rasock);

rasock = -1;

return 1;

}

/* Tell kernel dhcp6c pid, kernel will send messages to dhcp6c when it receive ICMPv6 RA */

/* Fix IPv6 Ready logo rfc3315 */

memset(&dest_addr, 0, sizeof(dest_addr));

dest_addr.nl_family = AF_NETLINK;

dest_addr.nl_pid = 0;

dest_addr.nl_groups = 0;

nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));

if(!nlh){

printf("malloc nlmsghdr error!\n");

close(rasock);

return -1;

}

nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);

nlh->nlmsg_pid = pid;

nlh->nlmsg_flags = 0;

sprintf(NLMSG_DATA(nlh), "%d", pid);

iov.iov_base = (void *)nlh;

iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);

memset(&msg, 0, sizeof(msg));

msg.msg_name = (void *)&dest_addr;

msg.msg_namelen = sizeof(dest_addr);

msg.msg_iov = &iov;

msg.msg_iovlen = 1;

printf("state_smg\n");

state_smg = sendmsg(rasock, &msg, 0);

if(state_smg == -1)

{

printf("get error sendmsg = %s\n",strerror(errno));

}

}

2. 等待接收消息

// add to read sockets

if (rasock >= 0) {

FD_SET(rasock, &r);

maxsock = (rasock > maxsock) ? rasock : maxsock;

}

//wait

ret = select(maxsock + 1, &r, NULL, NULL, w);

if (FD_ISSET(rasock, &r)) {

printf("%s: have receive the ra message\n", __func__);

dhcp6_ra_recv(); //send solicit

}

时间: 2024-10-13 08:08:05

Kernel与用户进程通信的相关文章

系统进程和用户进程通信

我的用户进程需要和我的服务进程通信,通过文件映射.事件的方式通信时需要注意: 1.需要低权限 var SecMem: SECURITY_ATTRIBUTES; aSD: SECURITY_DESCRIPTOR;begin FExistsAlready := False; InitializeSecurityDescriptor(@aSD, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(@aSD, True, nil, False

Linux间的进程通信;以及子进程的创建

1 "-----第六天-----------------------------------------------------------------------------" 2 3 1.版本控制:svn/git; 4 5 2.进程的概念: 6 1)程序和进程: 7 每个进程操作系统会为它分配 0-4G 的虚拟内存空间(32位操作系统): 其中0-3G为用户内存空间,进程可以对它进行读写操作: 3G - 4G 为系统内核空间,进程没有读写权限. 8 进程只能读写用户空间,没有权限读

Linux程序设计学习笔记----System V进程通信(共享内存)

转载请注明出处:http://blog.csdn.net/suool/article/details/38515863 共享内存可以被描述成内存一个区域(段)的映射,这个区域可以被更多的进程所共享.这是IPC机制中最快的一种形式,因为它不需要中间环节,而是把信息直接从一个内存段映射到调用进程的地址空间. 一个段可以直接由一个进程创建,随后,可以有任意多的进程对其读和写.但是,一旦内存被共享之后,对共享内存的访问同步需要由其他 IPC 机制,例如信号量来实现.象所有的System V IPC 对象

Linux程序设计学习笔记----System V进程通信之消息队列

一个或多个进程可向消息队列写入消息,而一个或多个进程可从消息队列中读取消息,这种进程间通讯机制通常使用在客户/服务器模型中,客户向服务器发送请求消息,服务器读取消息并执行相应请求.在许多微内核结构的操作系统中,内核和各组件之间的基本通讯方式就是消息队列.例如,在 MINIX 操作系统中,内核.I/O 任务.服务器进程和用户进程之间就是通过消息队列实现通讯的. Linux中的消息可以被描述成在内核地址空间的一个内部链表,每一个消息队列由一个IPC的标识号唯一的标识.Linux 为系统中所有的消息队

Linux下的进程类别(内核线程、轻量级进程和用户进程)以及其创建方式--Linux进程的管理与调度(四)

本文声明 日期 内核版本 架构 作者 GitHub CSDN 2016-05-12 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的创建 本文中出现的,内核线程,轻量级进程,用户进程,用户线程等概念,如果不太熟悉, 可以参见 内核线程.轻量级进程.用户线程三种线程概念解惑(线程≠轻量级进程) Linux进程类别 虽然我们在区分Linux进程类别, 但是我还是想说Linux下只有一种类型的进程,那就是task_str

进程通信(转)

1.定义: 进程通讯是指进程之间的信息交换. 在进程之间要传送大量数据时,就需要使用进程通讯. 进程互斥和同步需要交换一定的信息,它们也可归为进程通讯,属于低级的进程通讯.低级的原因在于 (1).效率低,生产者每次只能向缓冲池投放一个产品(消息),消费者每次只能从缓冲池中取得一个消息 (2).通讯对用户不透明,OS职位进程之间的通讯提供了共享存储其. 2.进程通讯特点: 使用方便.OS隐藏了实现进程通讯的具体细节,向用户提供了一组用于实现高级通信的命令(原语),用户可方便的直接利用它实现进程之间

Qt的内部进程通信机制 [转]

Qt 作为一种跨平台的基于 C++ 的 GUI系统,能够提供给用户构造图形用户界面的强大功能.自从 1996 年 Qt 被 Trolltech公司发布以来,该系统成为世界上很多成功的图形用户应用所使用的主要系统.更为重要的是,Linux 操作系统的桌面环境系统 KDE 也是基于 Qt构造的.目前,Qt 已经提供了对包括 MS/Windows.Unix/X11 和嵌入式平台的支持,得到了越来越广泛的应用. 在 Qt 系统中,不仅有着构造完善的系统结构,而且为了满足用户对编写图形用户界面应用的种种需

进程通信

1.定义: 进程通讯是指进程之间的信息交换. 在进程之间要传送大量数据时,就需要使用进程通讯. 进程互斥和同步需要交换一定的信息,它们也可归为进程通讯,属于低级的进程通讯.低级的原因在于 (1).效率低,生产者每次只能向缓冲池投放一个产品(消息),消费者每次只能从缓冲池中取得一个消息 (2).通讯对用户不透明,OS职位进程之间的通讯提供了共享存储其. 2.进程通讯特点: 使用方便.OS隐藏了实现进程通讯的具体细节,向用户提供了一组用于实现高级通信的命令(原语),用户可方便的直接利用它实现进程之间

Linux进程通信——管道

进程间通信(IPC:Inner Proceeding Communication) 进程是操作系统实现程序独占系统运行的假象的方法,是对处理器.主存.I/O设备的抽象表示.每个进程都是一个独立的资源管理单元,每个进程所看到的是自己独占使用系统的假象,因此各个进程之间是不能够直接的访问对方进程的资源的,不同的进程之间进行信息交互需要借助操作系统提供的特殊的进程通信机制. 进程之间的通信,从物理上分,可以分为同主机的进程之间的通信和不同主机间的进程之间的通信.从通信内容方式上分,可以分为数据交互.同