|
|
|
|
参数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版本的内核时并没有发现这种处理过程,一般都是按下面的方法进行处理。
|
|
字段pid表示消息发送者进程 ID,也即源地址,对于内核,它为 0, dst_pid 表示消息接收者进程 ID,也即目标地址,如果目标为组或内核,它设置为 0,否则 dst_group 表示目标组地址,如果它目标为某一进程或内核,dst_group 应当设置为 0。
下面是参考网上使用netlink写的和内核通信的两个程序,一个是用户空间,一个是内核空间。
内核空间:netlink.c
#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 pid; int err; struct sock *nl_sk = NULL; int flag = 0; int stringlength(const char *s) { int slen = 0; for(; *s; s++){ slen++; } return slen; } void sendnlmsg(void) { struct sk_buff *skb_1; struct nlmsghdr *nlh; int len = NLMSG_SPACE(MAX_MSGSIZE); int slen = 0; char buffer[128]; const char *message="hello i am kernel"; 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"); } nlh = nlmsg_put(skb_1,0,0,0,MAX_MSGSIZE,0); NETLINK_CB(skb_1).pid = 0; NETLINK_CB(skb_1).dst_group = 0; slen = stringlength(message); memset(buffer,0,sizeof(buffer)); memcpy(buffer,message,slen); memcpy(NLMSG_DATA(nlh),buffer,slen+1); printk("my_net_link:send message '%s'.\n",(char *)NLMSG_DATA(nlh)); netlink_unicast(nl_sk,skb_1,pid,MSG_DONTWAIT); } 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(); break; } flag = 1; kfree_skb(skb); } } // Initialize netlink /* kernel 3.9.6中实例代码 struct netlink_kernel_cfg { unsigned int groups; unsigned int flags; void (*input)(struct sk_buff *skb); struct mutex *cb_mutex; void (*bind)(int group); }; netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg) 3.2.0-24中 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); */ static 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("wangpengqi"); 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 state = recvmsg(sock_fd, &msg, 0); if(state<0){ printf("state<1"); } printf("Received message: %s\n",(char *) NLMSG_DATA(nlh)); close(sock_fd); return 0; }
Makefile文件
[root@control netlink]# cat Makefile obj-m := netlink.o KERNELBUILD := /lib/modules/`uname -r`/build default: make -C $(KERNELBUILD) M=$(shell pwd) modules clean: rm -rf *.o .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers .*.d *.unsigned *.order