参考资料:

https://blog.csdn.net/zqixiao_09/article/details/77131283

https://www.cnblogs.com/lopnor/p/6158800.html

Netlink 是一种特殊的 socket,它是 Linux 所特有的,类似于 BSD 中的AF_ROUTE 但又远比它的功能强大,目前在最新的 Linux 内核(2.6.14)中使用netlink 进行应用与内核通信的应用很多,包括:路由 daemon(NETLINK_ROUTE),1-wire 子系统(NETLINK_W1),用户态 socket 协议(NETLINK_USERSOCK),防火墙(NETLINK_FIREWALL),socket 监视(NETLINK_INET_DIAG),netfilter 日志(NETLINK_NFLOG),ipsec 安全策略(NETLINK_XFRM),SELinux 事件通知(NETLINK_SELINUX),iSCSI 子系统(NETLINK_ISCSI),进程审计(NETLINK_AUDIT),转发信息表查询(NETLINK_FIB_LOOKUP),netlink connector(NETLINK_CONNECTOR),netfilter 子系统(NETLINK_NETFILTER),IPv6 防火墙(NETLINK_IP6_FW),DECnet 路由信息(NETLINK_DNRTMSG),内核事件向用户态通知(NETLINK_KOBJECT_UEVENT),通用 netlink(NETLINK_GENERIC)。

Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 netlink。

Netlink 相对于系统调用,ioctl 以及 /proc 文件系统而言具有以下优点:

1,为了使用 netlink,用户仅需要在 include/linux/netlink.h 中增加一个新类型的 netlink 协议定义即可, 如 #define NETLINK_MYTEST 17 然后,内核和用户态应用就可以立即通过 socket API 使用该 netlink 协议类型进行数据交换。但系统调用需要增加新的系统调用,ioctl 则需要增加设备或文件, 那需要不少代码,proc 文件系统则需要在 /proc 下添加新的文件或目录,那将使本来就混乱的 /proc 更加混乱。

问题:

增加了netlink协议后,需要重新编译内核吗?还是仅仅修改了头文件netlink.h就可以了呢?在后期的实验中,需要对这一问题进行验证。

2. netlink是一种异步通信机制,在内核与用户态应用之间传递的消息保存在socket缓存队列中,发送消息只是把消息保存在接收者的socket的接收队列,而不需要等待接收者收到消息,但系统调用与 ioctl 则是同步通信机制,如果传递的数据太长,将影响调度粒度。

异步通信与同步通信的区别:看接受者的响应方式。异步通讯是不需要接受者立即响应的

3.使用 netlink 的内核部分可以采用模块的方式实现,使用 netlink 的应用部分和内核部分没有编译时依赖,但系统调用就有依赖,而且新的系统调用的实现必须静态地连接到内核中,它无法在模块中实现,使用新系统调用的应用在编译时需要依赖内核。

可以像编写驱动模块一样的实现方式来实现netlink部分。

4.netlink 支持多播,内核模块或应用可以把消息多播给一个netlink组,属于该neilink 组的任何内核模块或应用都能接收到该消息,内核事件向用户态的通知机制就使用了这一特性,任何对内核事件感兴趣的应用都能收到该子系统发送的内核事件,在后面的文章中将介绍这一机制的使用。

5.内核可以使用 netlink 首先发起会话,但系统调用和 ioctl 只能由用户应用发起调用。

内核主动向用户应用发起数据

6.netlink 使用标准的 socket API,因此很容易使用,但系统调用和 ioctl则需要专门的培训才能使用。

NETLINK_GENERIC是一个通用的协议类型,它是专门为用户使用的,因此,用户可以直接使用它,而不必再添加新的协议类型。

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <linux/netlink.h>#define NETLINK_USER 22
#define USER_MSG (NETLINK_USER + 1)
#define USER_PORT 50  /*此处是写死了,可以用进程ID,表示来自用户态的唯一进程*/MODULE_LICENSE("GPL");
MODULE_AUTHOR("arvik");
MODULE_DESCRIPTION("netlink_demo");static void test_netlink_rcv(struct sk_buff *skb);struct netlink_kernel_cfg cfg = {.input = test_netlink_rcv,/*...*/
};
static struct sock *test_netlink_sock = NULL;int send_msg(int8_t *pbuf, uint16_t len)
{struct sk_buff *nl_skb;struct nlmsghdr *nlh;int ret;nl_skb = nlmsg_new(len, GFP_ATOMIC);if (!nl_skb) {printk("netlink_alloc_skb error\n");return -1;}/*将header填充到skb中*/nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0);if (nlh == NULL) {printk("put error\n");nlmsg_free(nl_skb);return -1;}/*拷贝data*/memcpy(nlmsg_data(nlh), pbuf, len);/*发送*/ret = netlink_unicast(test_netlink_sock, nl_skb, USER_PORT, MSG_DONTWAIT);return ret;
}static void test_netlink_rcv(struct sk_buff *skb)
{struct nlmsghdr *nlh = NULL;void *data = NULL;printk("skb->len %u\n", skb->len);if (skb->len >= nlmsg_total_size(0)){nlh = nlmsg_hdr(skb);data = NLMSG_DATA(nlh);if (data) {printk("kernel receive date : %s\n", (int8_t *)data);send_msg(data, nlmsg_len(nlh));}}
}static int __init test_netlink_init(void)
{printk("test netlink init\n");test_netlink_sock = netlink_kernel_create(&init_net, USER_MSG, &cfg);    if (test_netlink_sock == NULL) {printk("test netlink init error\n");return -1;}printk("test netlink init ok\n");return 0;
}
static void __exit test_netlink_exit(void)
{netlink_kernel_release(test_netlink_sock);test_netlink_sock = NULL;printk("test netlink exit\n");
}module_init(test_netlink_init);
module_exit(test_netlink_exit);

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/netlink.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>#define NETLINK_USER 22
#define USER_MSG (NETLINK_USER + 1)#define MSG_LEN 100#define MAX_PLOAD 100struct _my_msg {struct nlmsghdr hdr;int8_t data[MSG_LEN];
};int main()
{char *data = "hello kernel";socklen_t addr_len;struct sockaddr_nl local, dest_addr;int skfd;struct nlmsghdr *nlh = NULL;struct _my_msg info;int ret;//创建socketskfd = socket(AF_NETLINK, SOCK_RAW, USER_MSG);if (skfd == (-1)) {fprintf(stderr, "create socket error...%s\n", strerror(errno));return (-1);}/*绑定*/memset(&local, 0, sizeof(local));local.nl_family =  AF_NETLINK;local.nl_pid = 50;  /*此处的pid通常用进程ID,表示来自用户态的唯一进程*/local.nl_groups = 0;if (bind(skfd, (struct sockaddr *)&local, sizeof(local)) != 0) {fprintf(stderr, "bind error\n");close(skfd);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;/*填写data*/nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PLOAD));memset(nlh, 0, sizeof(struct nlmsghdr));nlh->nlmsg_len = NLMSG_SPACE(MAX_PLOAD);nlh->nlmsg_flags = 0;nlh->nlmsg_type = 0;nlh->nlmsg_seq = 0;nlh->nlmsg_pid = local.nl_pid;memcpy(NLMSG_DATA(nlh), data, strlen(data));ret = sendto(skfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_nl));if (ret < 0) {
//        fprintf(stderr, "sendto error\n");perror("sendto error: ");close(skfd);return (-1);}printf("wait kernel msg!\n");memset(&info, 0, sizeof(info));/*接受信息*/ret = recvfrom(skfd, &info, sizeof(struct _my_msg), 0, (struct sockaddr *)&dest_addr, &addr_len);if (ret <= 0) {
//        fprintf(stderr, "recv from kernel  error\n");perror("recv from kernel error: ");close(skfd);return (-1);}printf("msg receive from kernel : %s\n", info.data);close(skfd);free((void *)nlh);close(skfd);return 0;
}

转载于:https://www.cnblogs.com/rivsidn/p/10493954.html

Linux 内核态与用户态通信 netlink相关推荐

  1. linux 内核信号量与用户态信号量(system v,信号量在Linux多线程机制中的应用

    [摘 要]本文以信号量原理为基础,重点阐述信号量在Linux多线程同步机制中的实现特色. [关键词]信号量:Linux:多线程:同步 1 信号量 1965年E. W. Dijkstra首次提出信号量的 ...

  2. Linux内核态之间进程通信,内核态和用户态通信(二)--实现

    本文主要使用netlink套接字实现中断环境与用户态进程通信. 系统环境:基于linux 2.6.32.27 和 linux 3.16.36 Linux内核态和用户态进程通信方法的提出和实现 用户上下 ...

  3. linux 用户态 内核态 通信,procfs(从0开始,内核态和用户态通信charpter2)

    这篇博文将针对linux内核态与用户态通信方式中的procfs进行详细的学习. /proc主要存放内核的一些控制信息,所以这些信息大部分的逻辑位置位于内核控制的内存,在/proc下使用ls -l你会发 ...

  4. linux内核态和用户态

    参考文章: linux系统内核空间与用户空间通信的实现与分析: http://www.ibm.com/developerworks/cn/linux/l-netlink/ 进程上下文VS中断上下文: ...

  5. Linux的init进程(内核态到用户态的变化)

    init进程,也就是内核启动3个进程中的进程1: init进程完成了从内核态向用户态的转变: (1)init进程是比较特殊,一个进程两个状态,init刚开始运行时是内核态,他属于内核线程,然后他自己运 ...

  6. Linux 操作系统原理 — 内核态与用户态

    目录 文章目录 目录 Linux 的内核态与用户态 系统调用(System Call) Shell 用户态和内核态的切换 进程的用户空间和内核空间的内存布局 内核空间 用户空间 Linux 的内核态与 ...

  7. 【Linux 内核】Linux 内核体系架构 ( 硬件层面 | 内核空间 | 用户空间 | 内核态与用户态切换 | 系统调用 | 体系结构抽象层 )

    文章目录 一.Linux 内核体系架构 二.内核态与用户态切换 ( 系统调用层 ) 三.体系结构抽象层 一.Linux 内核体系架构 Linux 内核最初的源码不足一万行 , 当前的 Linux 内核 ...

  8. linux c程序中内核态与用户态内存存储问题

    Unix/Linux的体系架构 如上图所示,从宏观上来看,Linux操作系统的体系架构分为用户态和内核态(或者用户空间和内核).内核从本质上看是一种软件--控制计算机的硬件资源,并提供上层应用程序运行 ...

  9. 【转】linux内核态和用户态的区别

    原文网址:http://www.mike.org.cn/articles/linux-kernel-mode-and-user-mode-distinction/ 内核态与用户态是操作系统的两种运行级 ...

最新文章

  1. Debian 9.x “stretch“ 解决 /etc/rc.local 开机启动问题
  2. cvThreshold()函数理解
  3. wpf Combobox 样式的问题
  4. 一套完整的导视设计案例_色彩导视艺术:乌克兰基辅语言学校导视设计案例
  5. mysql多客户端数据不同步_一种多终端设备上的数据同步方法
  6. bitcount方法详解_Java Long类的bitCount()方法和示例
  7. 解决“DNS_PROBE_FINISHED_NXDOMAIN”问题
  8. Java基础学习总结(137)——Java ClassLoader再总结
  9. python自动化--接口请求及封装
  10. mysql主从复制不同步案例_mysql主从复制不同步的问题
  11. hp6960无法连接计算机,惠普6960驱动
  12. iOS远程推送--APNs详解
  13. Vue简易图片手风琴组件,包含宽度适应(JS操作CSS实现)
  14. win32 005 实模式
  15. 计算机视觉中的变分方法-扩散(Diffusion)
  16. 【Linux】冒险Apache
  17. openofdm中complex_to_mag的分析
  18. 无锡设计培训——室内设计方案图纸包括哪些?
  19. Codeforces:div3_719 记录
  20. 培训机构到底好不好?学历重要吗?java

热门文章

  1. 如何处理SAP Fiori Launchpad错误消息:Could not start the app due to a configuration problem
  2. 推荐一个好用而且免费的XML文件查看工具,高效,易用而且可定制
  3. SAP CRM HANA live report的数据源
  4. SAP CRM 产品主数据和附件(Attachment)的模型关系
  5. 如何使用ABAP代码反序列化JSON字符串成ABAP结构
  6. 为什么ABAP整型的1转成string之后,后面会多个空格 1
  7. c++ file* 句柄泄漏_C++核心准则?讨论:持有没有被句柄管理的资源时切勿抛出异常...
  8. 边缘计算应用场景_云计算与边缘计算协同九大应用场景(2019年)发布(附PPT解读)...
  9. html显示php值,HTML窗体加载显示通过PHP的十六进制值
  10. android 一个字符串分两行显示_重新梳理Android权限管理