netlink的特点
netlink提供了一种在用户态和内核态之间进行数据传递的方式;
(1) 是一种异步的通信机制,传递的数据会放在socket的缓存队列中;
(2) 内核可以主动发送数据给用户空间;
(3) 能够在内核模块中使用;
(4) 支持组播;
(5) 使用套接字编程;
测试例程
用户态例程
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <sys/socket.h> 6 #include <linux/netlink.h> 7 8 #define MAX_PAYLOAD 64 9 10 #define NETLINK_TEST 25 11 12 int main(int argc, char * argv[]) 13 { 14 int sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST); 15 if (sock_fd < 0) { 16 perror("create socket failed! "); 17 return -1; 18 } 19 20 struct sockaddr_nl src_addr; 21 memset(&src_addr, 0, sizeof(struct sockaddr_nl)); 22 src_addr.nl_family = AF_NETLINK; 23 src_addr.nl_pid = getpid(); 24 src_addr.nl_groups = 0; 25 26 if (bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(struct sockaddr)) < 0) { 27 perror("bind socket failed! "); 28 close (sock_fd); 29 return -1; 30 } 31 32 struct sockaddr_nl dest_addr; 33 34 memset(&dest_addr, 0, sizeof(struct sockaddr_nl)); 35 dest_addr.nl_family = AF_NETLINK; 36 dest_addr.nl_pid = 0; 37 dest_addr.nl_groups = 0; 38 39 struct nlmsghdr *nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); 40 if (nlh == NULL) { 41 perror("malloc nlmsghdr failed! "); 42 close(sock_fd); 43 return -1; 44 } 45 46 memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); 47 nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); 48 nlh->nlmsg_pid = getpid(); 49 nlh->nlmsg_flags = 0; 50 51 strcpy(NLMSG_DATA(nlh), "Hello kernel!"); 52 53 struct iovec iov; 54 iov.iov_base = (void *)nlh; 55 iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD); 56 57 struct msghdr msg; 58 memset(&msg, 0, sizeof(struct msghdr)); 59 msg.msg_name = (void *)&dest_addr; 60 msg.msg_namelen = sizeof(struct sockaddr_nl); 61 msg.msg_iov = &iov; 62 msg.msg_iovlen = 1; 63 64 if (sendmsg(sock_fd, &msg, 0) < 0) { 65 perror("send msg failed! "); 66 free(nlh); 67 close(sock_fd); 68 return -1; 69 } 70 71 printf("send msg: %s ", (char *)NLMSG_DATA(nlh)); 72 73 memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); 74 75 if (recvmsg(sock_fd, &msg, 0) < 0) { 76 perror("recv msg failed! "); 77 free(nlh); 78 close(sock_fd); 79 return -1; 80 } 81 82 printf("receive msg: %s ", (char *)NLMSG_DATA(nlh)); 83 84 85 free(nlh); 86 close(sock_fd); 87 88 return 0; 89 }
内核态例程
1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <net/sock.h> 4 #include <net/netlink.h> 5 #include <linux/string.h> 6 7 #define NETLINK_TEST 25 8 #define MAX_MSGSIZE 64 9 10 static struct sock *nl_sock = NULL; 11 12 static void send_msg(char *msg, int pid) 13 { 14 struct sk_buff *skb = NULL; 15 struct nlmsghdr *nlh = NULL; 16 int msglen = strlen(msg); 17 18 if (msg == NULL || nl_sock == NULL) { 19 return; 20 } 21 22 skb = alloc_skb(NLMSG_SPACE(MAX_MSGSIZE), GFP_KERNEL); 23 if (skb == NULL) { 24 printk(KERN_ERR "allock skb failed! "); 25 return; 26 } 27 28 nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0); 29 NETLINK_CB(skb).portid = 0; 30 NETLINK_CB(skb).dst_group = 0; 31 memcpy(NLMSG_DATA(nlh), msg, msglen + 1); 32 33 printk("send msg: %s ", (char *)NLMSG_DATA(nlh)); 34 35 netlink_unicast(nl_sock, skb, pid, MSG_DONTWAIT); 36 } 37 38 static void recv_msg(struct sk_buff *in_skb) 39 { 40 struct sk_buff *skb = NULL; 41 struct nlmsghdr *nlh = NULL; 42 43 skb = skb_get(in_skb); 44 if (skb->len >= nlmsg_total_size(0)) { 45 nlh = nlmsg_hdr(skb); 46 47 printk("receive msg: %s ", (char *)NLMSG_DATA(nlh)); 48 49 send_msg("Hello app!", nlh->nlmsg_pid); 50 51 kfree_skb(skb); 52 } 53 } 54 55 static int netlink_init(void) 56 { 57 struct netlink_kernel_cfg netlink_cfg; 58 memset(&netlink_cfg, 0, sizeof(struct netlink_kernel_cfg)); 59 netlink_cfg.input = recv_msg; 60 61 nl_sock = netlink_kernel_create(&init_net, NETLINK_TEST, &netlink_cfg); 62 if (nl_sock == NULL) { 63 printk(KERN_ERR "netlink: netlink_kernel_create failed! "); 64 return -1; 65 } 66 67 printk("netlink: netlink module init success! "); 68 return 0; 69 } 70 71 static void netlink_exit(void) 72 { 73 if (nl_sock != NULL) { 74 sock_release(nl_sock->sk_socket); 75 } 76 77 printk("netlink: netlink module exit success! "); 78 } 79 80 module_init(netlink_init); 81 module_exit(netlink_exit); 82 MODULE_LICENSE("GPL");
Makefile
1 ifneq ($(KERNELRELEASE),) 2 obj-m :=netlink_kernel.o 3 else 4 KERNELDIR ?=/lib/modules/$(shell uname -r)/build 5 PWD :=$(shell pwd) 6 default: 7 $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 8 clean: 9 rm -rf *.o *.mod.c *.ko *.symvers *.order *.makers 10 endif
测试结果
用户态:
1 [root@localhost netlink]# ./netlink_app 2 send msg: Hello kernel! 3 receive msg: Hello app!
内核态:
1 [root@localhost netlink]# insmod netlink_kernel.ko 2 [root@localhost netlink]# cat /proc/kmsg 3 <4>[19211.917913] receive msg: Hello kernel! 4 <4>[19211.917916] send msg: Hello app!
本文参考: