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