netlink

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!\n");
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!\n");
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!\n");
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!\n");
66         free(nlh);
67         close(sock_fd);
68         return -1;
69     }
70 
71     printf("send msg: %s\n", (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!\n");
77         free(nlh);
78         close(sock_fd);
79         return -1;
80     }
81         
82     printf("receive msg: %s\n", (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!\n");
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\n", (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\n", (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!\n");
64         return -1;
65     }
66     
67     printk("netlink: netlink module init success!\n");
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!\n");
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!

 

本文参考:

http://blog.chinaunix.net/uid-28541347-id-5578403.html

http://blog.csdn.net/ganshuyu/article/details/30241313

 

posted @ 2019-10-28 20:50  AlexAlex  阅读(536)  评论(0编辑  收藏  举报