一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

Linux|Centos|Ubuntu|系統(tǒng)進(jìn)程|Fedora|注冊(cè)表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服務(wù)器之家 - 服務(wù)器系統(tǒng) - Linux - linux下用戶程序同內(nèi)核通信詳解(netlink機(jī)制)

linux下用戶程序同內(nèi)核通信詳解(netlink機(jī)制)

2022-02-25 17:22Quagger Linux

這篇文章主要介紹了linux下用戶程序同內(nèi)核通信詳解(netlink機(jī)制),涉及netlink,內(nèi)核模塊,用戶程序的介紹等相關(guān)內(nèi)容,小編覺得還是挺不錯(cuò)的,這里分享給大家,需要的朋友可以參考下

簡(jiǎn)介

linux下用戶程序同內(nèi)核通信的方式一般有ioctl, proc文件系統(tǒng),剩下一個(gè)就是Netlink套接字了。 這里先介紹下netlink。

Netlink 是一種在內(nèi)核與用戶應(yīng)用間進(jìn)行雙向數(shù)據(jù)傳輸?shù)姆浅:玫姆绞剑脩魬B(tài)應(yīng)用使用標(biāo)準(zhǔn)的 socket API 就可以使用 netlink 提供的強(qiáng)大功能,內(nèi)核態(tài)需要使用專門的內(nèi)核 API 來使用 netlink。

Netlink 相對(duì)于系統(tǒng)調(diào)用,ioctl 以及 /proc 文件系統(tǒng)而言具有以下優(yōu)點(diǎn):

1,為了使用 netlink,用戶僅需要在 include/linux/netlink.h 中增加一個(gè)新類型的 netlink 協(xié)議定義即可, 如 #define NETLINK_MYTEST 17 然后,內(nèi)核和用戶態(tài)應(yīng)用就可以立即通過 socket API 使用該 netlink 協(xié)議類型進(jìn)行數(shù)據(jù)交換。但系統(tǒng)調(diào)用需要增加新的系統(tǒng)調(diào)用,ioctl 則需要增加設(shè)備或文件, 那需要不少代碼,proc 文件系統(tǒng)則需要在 /proc 下添加新的文件或目錄,那將使本來就混亂的 /proc 更加混亂。

2. netlink是一種異步通信機(jī)制,在內(nèi)核與用戶態(tài)應(yīng)用之間傳遞的消息保存在socket緩存隊(duì)列中,發(fā)送消息只是把消息保存在接收者的socket的接 收隊(duì)列,而不需要等待接收者收到消息,但系統(tǒng)調(diào)用與 ioctl 則是同步通信機(jī)制,如果傳遞的數(shù)據(jù)太長(zhǎng),將影響調(diào)度粒度。

3.使用 netlink 的內(nèi)核部分可以采用模塊的方式實(shí)現(xiàn),使用 netlink 的應(yīng)用部分和內(nèi)核部分沒有編譯時(shí)依賴,但系統(tǒng)調(diào)用就有依賴,而且新的系統(tǒng)調(diào)用的實(shí)現(xiàn)必須靜態(tài)地連接到內(nèi)核中,它無法在模塊中實(shí)現(xiàn),使用新系統(tǒng)調(diào)用的應(yīng)用在編譯時(shí)需要依賴內(nèi)核。

4.netlink 支持多播,內(nèi)核模塊或應(yīng)用可以把消息多播給一個(gè)netlink組,屬于該neilink 組的任何內(nèi)核模塊或應(yīng)用都能接收到該消息,內(nèi)核事件向用戶態(tài)的通知機(jī)制就使用了這一特性,任何對(duì)內(nèi)核事件感興趣的應(yīng)用都能收到該子系統(tǒng)發(fā)送的內(nèi)核事件,在 后面的文章中將介紹這一機(jī)制的使用。

5.內(nèi)核可以使用 netlink 首先發(fā)起會(huì)話,但系統(tǒng)調(diào)用和 ioctl 只能由用戶應(yīng)用發(fā)起調(diào)用。

6.netlink 使用標(biāo)準(zhǔn)的 socket API,因此很容易使用,但系統(tǒng)調(diào)用和 ioctl則需要專門的培訓(xùn)才能使用。

下面這兩部分代碼主要的目的是用netlink機(jī)制實(shí)現(xiàn)用戶程序和內(nèi)核的通信。 具體就是用戶程序執(zhí)行./netlink -S [我是參數(shù)] 或./netlink -G 時(shí),內(nèi)核會(huì)返回"S know you!" 和“I know you!” 這兩種字符串, 然后輸出。 內(nèi)核和用戶程序均加有打印。

內(nèi)核模塊

1. Makefile依賴的編譯規(guī)則 ruler.dir

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PWD := $(shell pwd)
 
all: modules romfs
 
modules:
 $(MAKE) -C $(KDIR) M=$(PWD) modules
 @echo $(OBJ)
 
modules_install:
 $(MAKE) -C $(KDIR) M=$(PWD) modules_install
 
romfs:
 cp -rf *.ko $(MODULES_BUILD_DIR)
 
clean:
 rm *.o *.ko *.mod.* Module.* modules.*
 rm -rf $(MODULES_BUILD_DIR)
 
obj-m := $(MOD_NAME).o

2.Makefile

?
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
KERNEL_MODULES := netlink
 
export MODULES_ROOT_DIR := $(shell pwd)
export MODULES_BUILD_DIR := $(MODULES_ROOT_DIR)/build
export KDIR := /lib/modules/$(shell uname -r)/build #這行是為了取出系統(tǒng)下內(nèi)核的目錄(ubuntu)
 
all: init modules romfs
 
init:
 mkdir -p $(MODULES_BUILD_DIR)
 
modules:$(patsubst %, _dir_%, $(KERNEL_MODULES))
 
$(patsubst %, _dir_%, $(KERNEL_MODULES)):
 @echo
 @echo Building $(patsubst _dir_%, %, $@)
 $(MAKE) -C $(patsubst _dir_%, %, $@) all
 
 
romfs: $(patsubst %, _romfs_%, $(KERNEL_MODULES))
$(patsubst %, _romfs_%, $(KERNEL_MODULES)):
 $(MAKE) -C $(patsubst _romfs_%, %, $@) romfs
 
 
clean: $(patsubst %, _clean_%, $(KERNEL_MODULES))
 $(RM) $(BUILD_DIR)
$(patsubst %, _clean_%, $(KERNEL_MODULES)):
 @echo
 @echo Cleaning $(patsubst _dir_%, %, $@)
 $(MAKE) -C $(patsubst _clean_%, %, $@) clean
 
.PHONY:

3. ./netlink/netlink.c

?
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
 * netlink.c
 *
 * Created on: 2014 *  Author: cr
 */
 
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include "usrlink.h"
 
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("MDAXIA");
 
struct sock *netlink_fd;
 
 
static void netlink_to_user(int dest, void *buf, int len)
{
 struct nlmsghdr *nl;
 struct sk_buff *skb;
 int size;
 
 size = NLMSG_SPACE(len);
 skb = alloc_skb(size, GFP_ATOMIC);
 if(!skb || !buf)
 {
  printk(KERN_ALERT "netlink_to_user skb of buf null! ");
  return;
 }
 nl = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0);
 NETLINK_CB(skb).pid = 0;
 NETLINK_CB(skb).dst_group = 0;
 
 memcpy(NLMSG_DATA(nl), buf, len);
 nl->nlmsg_len = (len > 2) ? (len - 2):len;
 
 netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT);
 printk(KERN_ALERT "K send packet success ");
}
 
static int process_hello_get(int dest, void *buf, int len)
{
 printk(KERN_ALERT "In process_hello get! ");
 memcpy(buf, "I known you !", 13);
 netlink_to_user(dest, buf, 13);
 return NET_OK;
}
 
static int process_hello_set(int dest, void *buf, int len)
{
 printk(KERN_ALERT "In process_hello set! %s ", (char *)buf);
 memcpy(buf, "S known you !", 13);
 netlink_to_user(dest, buf, 13);
 return NET_OK;
}
 
 
static void netlink_process_packet(struct nlmsghdr *nl)
{
 int ret;
 
 switch(nl->nlmsg_type)
 {
 case HELLO_GET:
  ret = process_hello_get(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
  break;
 case HELLO_SET:
  ret = process_hello_set(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
  break;
 default:break;
 }
}
 
static void netlink_recv_packet(struct sk_buff *__skb)
{
 struct sk_buff *skb;
 struct nlmsghdr *nlhdr;
 
 skb = skb_get(__skb);
 if(skb->len >= sizeof(struct nlmsghdr))
 {
  nlhdr = (struct nlmsghdr *)skb->data;
  if(nlhdr->nlmsg_len >= sizeof(struct nlmsghdr) &&
    __skb->len >= nlhdr->nlmsg_len)
  {
   netlink_process_packet(nlhdr);
  }
 }
 else
  printk(KERN_ALERT "Kernel receive msg length error! ");
}
 
static int __init netlink_init(void)
{
 netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);
 if(NULL == netlink_fd)
 {
  printk(KERN_ALERT "Init netlink! ");
  return -1;
 }
 printk(KERN_ALERT "Init netlink success! ");
 return 0;
}
 
static void __exit netlink_exit(void)
{
 netlink_kernel_release(netlink_fd);
 printk(KERN_ALERT "Exit netlink! ");
}
 
module_init(netlink_init);
module_exit(netlink_exit);

4. ./netlink/usrlink.h

?
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
/*
 * usrlink.h
 *
 * Created on: 2014騫?鏈?7鏃? *  Author: cr
 */
#ifndef USRLINK_H_
#define USRLINK_H_
 
#define USER_NETLINK_CMD 25
#define MAXMSGLEN   1024
 
typedef enum error_e {
 NET_ERROR,
 NET_OK,
 NET_PARAM,
 NET_MEM,
 NET_SOCK,
} netlink_err;
 
typedef enum module_e {
 HELLO_CMD = 1,
} netlink_module;
 
typedef enum type_e {
 HELLO_SET,
 HELLO_GET,
} netlink_type;
 
#endif /* USRLINK_H_ */

5. ./netlink/Makefile

?
1
2
3
4
5
6
7
MOD_NAME := netlink
 
$(MOD_NAME)-objs : netlink.o
 
-include $(MODULES_ROOT_DIR)/rules.dir
 
.PHONY:

6. 編譯方式

其中Makefile、rulers.dir 在Knetlink/下, netlink.c 、netlink.h 、Makefile在Knetlink/netlink/目錄下。 編譯時(shí)在Knetlink目錄下執(zhí)行Make即可

用戶程序

用戶程序的Makefile 這里就不放出了。 我是直接在eclipse下建的工程 自動(dòng)編譯的、...

1. netlink.c

?
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
/*
 * usrlink.c
 *
 * Created on: 2014騫?鏈?7鏃? *  Author: cr
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "usrlink.h"
 
int netlink_sock_init(netlink_sock *netlink_s, int module, int protocol)
{
 netlink_s->sock = socket(PF_NETLINK, SOCK_RAW, protocol);
 if(netlink_s->sock < 0)
  return NET_SOCK;
 memset(&netlink_s->src, 0 ,sizeof(netlink_s->src));
 netlink_s->src.nl_family = AF_NETLINK;
 netlink_s->src.nl_pid = module;
 netlink_s->src.nl_groups = 0;
 
 if(bind(netlink_s->sock, (struct sockaddr *)&netlink_s->src, sizeof(netlink_s->src)) < 0)
  return NET_SOCK;
 
 netlink_s->dest.nl_family = AF_NETLINK;
 netlink_s->dest.nl_pid = 0;
 netlink_s->dest.nl_groups = 0;
 
 return NET_OK;
}
 
int netlink_send(netlink_sock *netlink_s, int type, char *sbuf, int slen, char *rbuf, int *rlen)
{
 struct msghdr msg;
 struct nlmsghdr *nlhdr = NULL;
 struct iovec iov;
 int ret;
 
 nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAXMSGLEN));
 if(NULL == nlhdr)
  return NET_MEM;
 
 memcpy(NLMSG_DATA(nlhdr), sbuf, slen);
 nlhdr->nlmsg_len = NLMSG_SPACE(slen);
 nlhdr->nlmsg_pid = netlink_s->src.nl_pid;
 nlhdr->nlmsg_type = type;
 nlhdr->nlmsg_flags = 0;
 
 iov.iov_base = (void *)nlhdr;
 iov.iov_len = nlhdr->nlmsg_len;
 
 msg.msg_name = (void *)&(netlink_s->dest);
 msg.msg_namelen = sizeof(netlink_s->dest);
 msg.msg_iov = &iov;
 msg.msg_iovlen = 1;
 
 ret = sendmsg(netlink_s->sock, &msg, 0);
 if(ret < 0)
 {
  printf("Send fail ");
  goto error;
 }
 ret = recvmsg(netlink_s->sock, &msg, 0);
 if(ret < 0)
 {
  printf("Read fail ");
  goto error;
 }
 memcpy(rbuf, NLMSG_DATA(nlhdr), nlhdr->nlmsg_len);
 *rlen = nlhdr->nlmsg_len;
 return NET_OK;
 
error:
 free(nlhdr);
 return NET_SOCK;
}
 
int netlink_sock_deinit(netlink_sock *netlink_s)
{
 close(netlink_s->sock);
 memset(netlink_s, 0, sizeof(netlink_sock));
 return NET_OK;
}

2. netlink.h

?
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
/*
 * usrlink.h
 *
 * Created on: 2014 *  Author: cr
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/socket.h>
#include <linux/netlink.h>
#ifndef USRLINK_H_
#define USRLINK_H_
 
#define USER_NETLINK_CMD 25
#define MAXMSGLEN   1024
 
typedef enum error_e {
 NET_ERROR,
 NET_OK,
 NET_PARAM,
 NET_MEM,
 NET_SOCK,
} netlink_err;
 
typedef enum module_e {
 HELLO_CMD = 1,
} netlink_module;
 
typedef enum type_e {
 HELLO_SET,
 HELLO_GET,
} netlink_type;
 
typedef struct usr_sock_h {
 int sock;
 struct sockaddr_nl dest;
 struct sockaddr_nl src;
} netlink_sock;
 
int netlink_sock_init(netlink_sock *netlink_s, int module, int protocol);
int netlink_sock_deinit(netlink_sock *netlink_s);
int netlink_send(netlink_sock *netlink_s, int type, char *sbuf, int slen, char *rbuf, int *rlen);
 
#endif /* USRLINK_H_ */

3. main.c

?
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
/*
 * main.c
 *
 * Created on: 2014騫?鏈?7鏃? *  Author: cr
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "usrlink.h"
 
int parse_ret(int ret)
{
 switch(ret)
 {
 case NET_OK:
  return ret;
 case NET_ERROR:
  printf("error ");
  goto exit_p;
 case NET_MEM:
  printf("Memory error ");
  goto exit_p;
 case NET_PARAM:
  printf("Param error ");
  goto exit_p;
 case NET_SOCK:
  printf("Socket error ");
  goto exit_p;
 default:break;
 }
exit_p:
 return NET_ERROR;
}
 
void usage(void)
{
 printf("Usage: Netlink -G <param> -S <param> ");
}
 
int main(int argc, char **argv)
{
 netlink_sock h_sock;
 char rbuf[1024];
 char sbuf[1024];
 int ret, type, slen = 0, rlen = 0;
 
 ret = netlink_sock_init(&h_sock, HELLO_CMD, USER_NETLINK_CMD);
 if(NET_OK != parse_ret(ret))
  goto exit_p;
 
 bzero(&rbuf, sizeof(rbuf));
 bzero(&sbuf, sizeof(sbuf));
 if(argc < 3)
 {
  usage();
  goto exit_p;
 }
 if(!strncmp("-G", argv[1], 2))
  type = HELLO_GET;
 else if(!strncmp("-S", argv[1], 2))
  type = HELLO_SET;
 
 strcpy(sbuf, argv[2]);
 slen = strlen(sbuf);
 ret = netlink_send(&h_sock, type, sbuf, slen, rbuf, &rlen);
 if(NET_OK != parse_ret(ret))
  goto exit_p;
 
 if(rlen > 0)
 {
  rbuf[rlen] = '';
  printf("K rep [len = %d]:%s ", rlen, rbuf);
 }
 printf("K[len = %d]: %s ", rlen, rbuf);
 
exit_p:
 netlink_sock_deinit(&h_sock);
 return 0;
}

總結(jié)

以上就是本文關(guān)于linux下用戶程序同內(nèi)核通信詳解(netlink機(jī)制)的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

原文鏈接:http://blog.csdn.net/daydring/article/details/24000081

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久精品国产欧美日韩99热 | 九九热视频免费观看 | 日韩小视频在线观看 | 日本69视频在线观看 | 日韩亚洲国产激情在线观看 | 性xxxx18学生第一次出血 | 免费一级欧美片在线观看 | 欧美日韩精品一区二区三区视频播放 | gaygayas男男免费中国 | 四虎永久网址影院 | 欧美激烈精交gif动态图18p | 国产巨大bbbb俄罗斯 | 国产精品免费一级在线观看 | 国产高清自拍 | 香蕉久久一区二区不卡无毒影院 | 按摩椅play啊太快了h | 欧美日本道免费一区二区三区 | 爆操萝莉| 草榴色导航 | 欧美一级片观看 | 闺蜜的样子小说安沁在线阅读 | 国产免费精彩视频 | 九九精品免费视频 | 午夜爽喷水无码成人18禁三级 | 国产欧美日韩亚洲精品区2345 | 91传媒制片厂制作传媒破解版 | 天美传媒影视在线免费观看 | 爱情岛论坛亚洲自拍 | 91小视频在线观看免费版高清 | 亚洲国产精品久久网午夜小说 | 日产中文乱码卡一卡二 | 亚洲欧美日韩另类精品一区二区三区 | 亚洲图片一区二区 | 99超级碰碰成人香蕉网 | 精品国产品在线18年 | 国内在线观看 | 青青热久久综合网伊人 | 亚洲www美色 | 变态人shou交小说 | 日本又黄又裸一级大黄裸片 | 草女人逼|