Linux中与内核通信的Netlink机制
来源:互联网 发布:电力数据采集系统 编辑:程序博客网 时间:2024/05/19 12:16
extern 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);
audit_sock = netlink_kernel_create(&init_net, NETLINK_AUDIT, 0,
audit_receive, NULL, THIS_MODULE);
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock)
extern 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);
参数unit表示netlink协议类型,如 NETLINK_MYTEST,参数input则为内核模块定义的netlink消息处理函数,当有消息到达这个netlink socket时,该input函数指针就会被引用。函数指针input的参数skb实际上就是函数netlink_kernel_create返回的 struct sock指针,sock实际是socket的一个内核表示数据结构,用户态应用创建的socket在内核中也会有一个struct sock结构来表示。
函数input()会在发送进程执行sendmsg()时被调用,这样处理消息比较及时,但是,如果消息特别长时,这样处理将增加系统调用sendmsg()的执行时间,也就是说当用户的程序调用sendmsg ()函数时,如果input()函数处理时间过长,也就是说input()函数不执行不完,用户程序调用的sendmsg()函数就不会返回。只有当内核空间中的input()函数返回时,用户调用的sendmsg()函数才会返回。对于这种情况,可以定义一个内核线程专门负责消息接收,而函数input 的工作只是唤醒该内核线程,这样sendmsg将很快返回。(这里网上的的说明)不过在查看Linux2.6.37版本的内核时并没有发现这种处理过程,一般都是按下面的方法进行处理。
nlsk = netlink_kernel_create(net, NETLINK_XFRM, XFRMNLGRP_MAX,
xfrm_netlink_rcv, NULL, THIS_MODULE);
static void xfrm_netlink_rcv(struct sk_buff *skb)
{
mutex_lock(&xfrm_cfg_mutex);
netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
mutex_unlock(&xfrm_cfg_mutex);
}
在netlink_rcv_skb()函数中进行接收处理。
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
u32 group, gfp_t allocation)
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_pid = 0;
NETLINK_CB(skb).dst_group = 1;
下面是参考网上使用netlink写的和内核通信的两个程序,一个是用户空间,一个是内核空间。
内核空间:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/types.h>
#include <net/sock.h>
#include <net/netlink.h>
#define NETLINK_TEST 25
#define MAX_MSGSIZE 1024
int stringlength(char *s);
void sendnlmsg(char * message);
int pid;
int err;
struct sock *nl_sk = NULL;
int flag = 0;
void sendnlmsg(char *message)
{
struct sk_buff *skb_1;
struct nlmsghdr *nlh;
int len = NLMSG_SPACE(MAX_MSGSIZE);/*计算消息总长:消息首部加上数据加度*/
int slen = 0;
if(!message || !nl_sk)
{
return ;
}
skb_1 = alloc_skb(len,GFP_KERNEL);
if(!skb_1)
{
printk(KERN_ERR "my_net_link:alloc_skb_1 error\n");
}
slen = stringlength(message);
nlh = nlmsg_put(skb_1,0,0,0,MAX_MSGSIZE,0);
NETLINK_CB(skb_1).pid = 0;
NETLINK_CB(skb_1).dst_group = 0;
message[slen]= '\0';
memcpy(NLMSG_DATA(nlh),message,slen+1);
printk("my_net_link:send message '%s'.\n",(char *)NLMSG_DATA(nlh));
netlink_unicast(nl_sk,skb_1,pid,MSG_DONTWAIT);
}
int stringlength(char *s)
{
int slen = 0;
for(; *s; s++){
slen++;
}
return slen;
}
void nl_data_ready(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) ;
pid = nlh->nlmsg_pid;
while(i--)
{
init_completion(&cmpl);
wait_for_completion_timeout(&cmpl,3 * HZ);
sendnlmsg("I am from kernel!");
}
flag = 1;
kfree_skb(skb);
}
}
// Initialize netlink
int netlink_init(void)
{
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 1,
nl_data_ready, NULL, THIS_MODULE);
if(!nl_sk){
printk(KERN_ERR "my_net_link: create netlink socket error.\n");
return 1;
}
printk("my_net_link_3: create netlink socket ok.\n");
return 0;
}
static void netlink_exit(void)
{
if(nl_sk != NULL){
sock_release(nl_sk->sk_socket);
}
printk("my_net_link: self module exited\n");
}
module_init(netlink_init);
module_exit(netlink_exit);
MODULE_AUTHOR("frankzfz");
MODULE_LICENSE("GPL");
#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>
#include <errno.h>
#define NETLINK_TEST 25
#define MAX_PAYLOAD 1024 // maximum payload size
int main(int argc, char* argv[])
{
int state;
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
struct msghdr msg;
int sock_fd, retval;
int state_smg = 0;
// Create a socket
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if(sock_fd == -1){
printf("error getting socket: %s", strerror(errno));
return -1;
}
// To prepare binding
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; // multi cast
retval = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
if(retval < 0){
printf("bind failed: %s", strerror(errno));
close(sock_fd);
return -1;
}
// To prepare recvmsg
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
if(!nlh){
printf("malloc nlmsghdr error!\n");
close(sock_fd);
return -1;
}
memset(&dest_addr,0,sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0;
dest_addr.nl_groups = 0;
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh),"Hello you!");
iov.iov_base = (void *)nlh;
iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
// iov.iov_len = nlh->nlmsg_len;
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(sock_fd,&msg,0);
if(state_smg == -1)
{
printf("get error sendmsg = %s\n",strerror(errno));
}
memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
printf("waiting received!\n");
// Read message from kernel
while(1){
printf("In while recvmsg\n");
state = recvmsg(sock_fd, &msg, 0);
if(state<0)
{
printf("state<1");
}
printf("In while\n");
printf("Received message: %s\n",(char *) NLMSG_DATA(nlh));
}
close(sock_fd);
return 0;
}
obj-m := netlink_k.o
KERNELBUILD := /lib/modules/`uname -r`/build
default:
@echo "BUILE Kmod"
@make -C $(KERNELBUILD) M=$(shell pwd) modules
gcc -o netlink_2 netlink_2.c
clean:
@echo " CLEAN kmod"
@rm -rf *.o
@rm -rf .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers .*.d
先运行内核代码netlink_k.ko,也就是在执行完makefile文件后,会生成一个netlink_k.ko文件,可以使用下面的命令进行安装,insmod netlink_k.ko,使用lsmod查看,当安装成功后,然后,执行./netlink用户空间程序,可以在另一个终端下执行dmesg命令,查看内核通信的情况。这里netlink程序向内核空间发送一个hello you!内核返回给一个I am from kernel!在这里使用了一个定时器,也就是每3秒中发送一次I am from kernel!只有内核把10个字符串全部发送完毕后,用户空间的sendmsg()才会返回,也就是在用户空间的netlink才会输出内核空间发送过来的数据,这里只有一个简单的程序,并没有什么实际的意义,因为,正如前面所说的一般情况下不会在回调函数中处理太多的东西,以免sendmsg()函数返回不及时。下面是使用dmesg命令输出的信息。
[873791.498039] my_net_link_3: create netlink socket ok.
[873810.263676] Message received:Hello
[873813.260848] my_net_link_4:send message 'I am from kernel!'.
[873816.260821] my_net_link_4:send message 'I am from kernel!'.
[873819.260860] my_net_link_4:send message 'I am from kernel!'.
[873822.260762] my_net_link_4:send message 'I am from kernel!'.
[873825.260883] my_net_link_4:send message 'I am from kernel!'.
[873828.260669] my_net_link_4:send message 'I am from kernel!'.
[873831.260714] my_net_link_4:send message 'I am from kernel!'.
[873834.260683] my_net_link_4:send message 'I am from kernel!'.
[873837.260666] my_net_link_4:send message 'I am from kernel!'.
[873840.260632] my_net_link_4:send message 'I am from kernel!'.
- Linux中与内核通信的Netlink机制
- Linux中与内核通信的Netlink机制(实例)
- Linux中与内核通信的Netlink机制(实例)
- Linux中与内核通信的Netlink机制(实例)
- socket的内核和上层通信机制(netlink) -- linux内核
- 《Linux 系统内核空间与用户空间通信的实现与分析》 Netlink 机制实现
- Linux-内核通信之netlink机制-详解
- Linux-内核通信之netlink机制-详解
- linux用户态和内核态通信之netlink机制
- linux用户态和内核态通信之netlink机制
- 使用netlink机制在内核与应用程序之间通信
- 使用netlink机制在内核与应用程序之间通信(转载)
- 使用netlink机制在内核与应用程序之间通信
- 使用netlink机制在内核与应用程序之间通信
- 使用netlink机制在内核与应用程序之间通信
- netlink---Linux下基于socket的内核和上层通信机制(上)
- netlink---Linux下基于socket的内核和上层通信机制
- netlink-Linux下基于socket的内核和上层通信机制
- GBK、GB2312、UTF-8
- 文件或目录访问记录
- NANDFLASH原理分析
- android tabwidget style
- 2012第25周官方应用市场Top Grossing动态
- Linux中与内核通信的Netlink机制
- 常用Linux命令记录( 持续更新中。。。)
- JBoss4 应用服务器Web开发人员参考手册(6):设置Web应用的Context Root
- Incompatible magic value 0
- ios学习--iOS下的Notification的使用
- 可用性测试——敏捷快速方案
- Nand Flash原理分析与编程
- 程序员职业发展的绊脚石-思想的枷锁
- Ubuntu安装AMD/ATI显卡驱动