netlink实现分析

合集下载

linux内核通信-netlink使用例子

linux内核通信-netlink使用例子

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),netlinkconnector(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 协议类型进行数据交换。

Netlink内核实现分析3

Netlink内核实现分析3

Netlink内核实现分析3Netlink IPC 数据结构#define NETLINK_ROUTE 0 /* Routing/device hook */#define NETLINK_UNUSED 1 /* Unused number */#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */#define NETLINK_SOCK_DIAG 4 /* socket monitoring */#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */#define NETLINK_XFRM 6 /* ipsec */#define NETLINK_SELINUX 7 /* SELinux event notifications */#define NETLINK_ISCSI 8 /* Open-iSCSI */#define NETLINK_AUDIT 9 /* auditing */#define NETLINK_FIB_LOOKUP 10#define NETLINK_CONNECTOR 11#define NETLINK_NETFILTER 12 /* netfilter subsystem */#define NETLINK_IP6_FW 13#define NETLINK_DNRTMSG 14 /* DECnet routing messages */#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */#define NETLINK_GENERIC 16/* leave room for NETLINK_DM (DM Events) */#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */#define NETLINK_ECRYPTFS 19#define NETLINK_RDMA 20#define NETLINK_CRYPTO 21 /* Crypto layer */#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG#define MAX_LINKS 32View Code/*其中(1)nl_family始终为AF_NETLINK;(2)nl_pad始终为0;(3)nl_pid为netlink套接字的单播地址,在发送消息时⽤于表⽰⽬的套接字的地址,在⽤户空间绑定时可以指定为当前进程的PID号(对于内核来说这个值为0)或者⼲脆不设置(在绑定bind时由内核调⽤netlink_autobind()设置为当前进程的PID),但需要注意的是当⽤户同⼀个进程中需要创建多个netlink套接字时则必须保证这个值是唯⼀的(⼀般在多线程中可以使⽤”pthread_self() << 16 | getpid()“这样的⽅法进⾏设置);(4)nl_groups表⽰组播组。

Netlink消息通信机制的IPSec VPN实现研究

Netlink消息通信机制的IPSec VPN实现研究

Netlink消息通信机制的IPSec VPN实现研究作者:黄超赵建平韦勇钢来源:《网络空间安全》2017年第11期摘要:文章分析研究Netlink机制对于Linux内核IPSec服务的支持,提出了一种基于Netlink消息通信机制的IPSec VPN实现方案。

方案由内核空间IPSec服务模块和用户空间IPSEC管理软件组成,两者通过Netlink进行通信,并为IPSec VPN提供了灵活、高效的IKE 协商机制和安全可靠IP数据包传输保障。

关键词:Netlink;IPSec VPN;IKE协商;用户空间;内核空间中图分类号:TP393 文献标识码:A1 引言VPN即虚拟专用网,是利用开放、不安全的公用网络作为基本传输介质,通过采用隧道封装、信息加密、用户认证和访问控制等技术形成专用的虚拟链路实现对信息传输过程的安全保护,从而向用户提供类似专用网络安全性能的网络服务技术。

IPSec是Internet工程任务组IETF定义的一套安全标准,包括一系列安全协议,为IP数据包传输提供安全保障。

Linux 虚拟地址空间为0到4G,划分为内核空间和用户空间两部分。

内核空间包括最高的1G字节,而用户空间包括较低的3G字节。

基于Linux 的IPSec VPN由内核IPSEC服务模块和用户空间IPSec管理软件组成。

内核IPSec模块在内核提供IP数据包的地址验证、数据完整性校验,数据机密性保护等业务,用户空间IPSec管理软件执行IKE密钥协商,密钥配置等业务。

其中IKE密钥协商用于产生通信双方可用于加解密的工作密钥。

Netlink是Linux提供的一种消息通信机制,用于内核空间和用户空间之间的信息传输。

本文提出了一种基于Netlink消息通信机制的IPSec VPN的实现方案。

本方案重点是设计用户空间IPSec管理软件,实现安全策略管理配置等功能,内核模块采用Linux内核原生IPSec服务模块。

2 Netlink机制对IPSEC的支持内核的 IPSEC 处理逻辑中包含SAD 和 SPD 两个策略数据库,其中 SAD 中包含了所有有效的用于保护通信的安全关联(SA),SPD中包含了使用的安全策略(SP)。

用户空间和内核空间通讯之Netlink

用户空间和内核空间通讯之Netlink

用户空间和内核空间通讯之Netlink引言Alan Cox在内核1.3版本的开发阶段最先引入了Netlink,刚开始时Netlink是以字符驱动接口的方式提供内核与用户空间的双向数据通信;随后,在2.1内核开发过程中,Alexey Kuznetsov将Netlink改写成一个更加灵活、且易于扩展的基于消息通信接口,并将其应用到高级路由子系统的基础框架里。

自那时起,Netlink就成了Linux内核子系统和用户态的应用程序通信的主要手段之一。

2001年,ForCES IETF委员会正式对Netlink进行了标准化的工作。

Jamal Hadi Salim提议将Netlink定义成一种用于网络设备的路由引擎组件和其控制管理组件之间通信的协议。

不过他的建议最终没有被采纳,取而代之的是我们今天所看到的格局:Netlink被设计成一个新的协议域,domain。

Linux之父托瓦斯曾说过“Linuxis evolution, not intelligent design”。

什么意思?就是说,Netlink也同样遵循了Linux的某些设计理念,即没有完整的规范文档,亦没有设计文档。

只有什么?你懂得---“Read the f**king source code”。

当然,本文不是分析Netlink 在Linux上的实现机制,而是就“什么是Netlink”以及“如何用好Netlink”的话题和大家做个分享,只有在遇到问题时才需要去阅读内核源码弄清个所以然。

<spanstyle="font-size:10.5pt;mso-bidi-font-size:11.0pt;font-family:宋体;mso-ascii-font-family:Calibri;mso-ascii-theme-font:minor-latin;mso-fareast-theme-font:minor-fareast;mso-hansi-font-family:Calibri;mso-hansi-theme-font:minor-latin ;mso-bidi-font-family:">什么是Netlink关于Netlink的理解,需要把握几个关键点:1、面向数据报的无连接消息子系统2、基于通用的BSD Socket架构而实现关于第一点使我们很容易联想到UDP协议,能想到这一点就非常棒了。

netlink用法

netlink用法

netlink用法1. 什么是netlinknetlink是Linux内核中一个用于内核和用户空间进程通信的机制。

它允许内核向用户空间应用程序发送消息,并提供了一种用于配置,管理和监视内核子系统的接口。

2. netlink的特性netlink的特性使其成为了Linux环境下进行内核和用户空间通信的重要工具,具有以下特点:2.1 强大而灵活netlink提供了一种灵活的通信机制,允许内核和用户空间之间进行双向通信。

应用程序可以通过发送消息给内核来请求信息,而内核也可以通过发送消息给应用程序来通知其发生的事件。

2.2 支持多种消息类型netlink支持多种消息类型,如路由信息、网络配置、接口状态等。

这使得开发者可以利用netlink来实现各种不同的功能。

2.3 可靠和高效netlink使用基于内存的套接字,相比于其他IPC机制(如管道和信号量),netlink是一种更加可靠和高效的通信机制。

它避免了不必要的内核空间与用户空间的拷贝,从而提高了系统的性能。

3. netlink的使用3.1 netlink的工作原理netlink通信的基本单位是消息(message),消息由一个头部(header)和一个有效载荷(payload)组成。

头部包含了消息的类型、源地址、目的地址等信息,有效载荷是实际的数据。

3.2 使用netlink库函数为了方便使用netlink,Linux提供了一组用户空间的库函数。

通过这些库函数,我们可以方便地发送和接收netlink消息。

3.2.1 创建netlink套接字首先,我们需要使用socket系统调用创建一个netlink套接字。

通过指定NETLINK_XXX作为协议参数,可以选择不同的netlink协议。

3.2.2 绑定套接字在创建套接字之后,我们需要使用bind函数将套接字与一个本地地址进行绑定。

这个本地地址可以是任意的netlink协议中定义的地址。

3.2.3 构造消息使用netlink库函数,我们可以方便地构造一个netlink消息。

netlink socket通信框架原理

netlink socket通信框架原理

netlink socket通信框架原理
Netlink socket是一种特殊的socket,用于实现用户空间和内核空间之间的通
信。

其通信原理如下:
1.发送消息时,消息只暂存在socket接收缓存中,不需要等待接收者立即处
理,因此Netlink是一种异步通信机制。

link基于BSD socket和AF_NETLINK地址簇,使用32位的端口号寻址
(PID),每个Netlink协议通常与一个或一组内核服务/组件相关联,如常用的NETLINK_ROUTE用于获取和设置路由与链路信息。

link机制在内核与应用程序之间通信时,无需启动一个内核线程,而是
通过另一个软中断调用用户事先指定的接收函数,因此对中断过程的支持
是其一大特点。

以上内容仅供参考,如需更多信息,建议查阅相关文献或咨询专业技术人员。

linux下netlink的使用简介

linux下netlink的使用简介

linux下netlink的使⽤简介⼀、什么是netlinkNetlink套接字是⽤以实现⽤户进程与内核进程通信的⼀种特殊的进程间通信(IPC) ,也是⽹络应⽤程序与内核通信的最常⽤的接⼝。

在Linux 内核中,使⽤netlink 进⾏应⽤与内核通信的应⽤有很多,如路由 daemon(NETLINK_ROUTE)⽤户态 socket 协议(NETLINK_USERSOCK)防⽕墙(NETLINK_FIREWALL)netfilter ⼦系统(NETLINK_NETFILTER)内核事件向⽤户态通知(NETLINK_KOBJECT_UEVENT)通⽤netlink(NETLINK_GENERIC)Netlink 是⼀种在内核与⽤户应⽤间进⾏双向数据传输的⾮常好的⽅式,⽤户态应⽤使⽤标准的 socket API 就可以使⽤ netlink 提供的强⼤功能,内核态需要使⽤专门的内核 API 来使⽤ netlink。

⼀般来说⽤户空间和内核空间的通信⽅式有三种:/proc、ioctl、Netlink。

⽽前两种都是单向的,⽽Netlink可以实现双⼯通信。

Netlink 相对于系统调⽤,ioctl 以及 /proc⽂件系统⽽⾔,具有以下优点:netlink使⽤简单,只需要在include/linux/netlink.h中增加⼀个新类型的 netlink 协议定义即可,(如 #define NETLINK_TEST 20然后,内核和⽤户态应⽤就可以⽴即通过socket API 使⽤该 netlink 协议类型进⾏数据交换)netlink是⼀种异步通信机制,在内核与⽤户态应⽤之间传递的消息保存在socket缓存队列中,发送消息只是把消息保存在接收者的socket的接收队列,⽽不需要等待接收者收到消息使⽤ netlink 的内核部分可以采⽤模块的⽅式实现,使⽤ netlink 的应⽤部分和内核部分没有编译时依赖netlink ⽀持多播,内核模块或应⽤可以把消息多播给⼀个netlink组,属于该neilink 组的任何内核模块或应⽤都能接收到该消息,内核事件向⽤户态的通知机制就使⽤了这⼀特性内核可以使⽤ netlink ⾸先发起会话Netlink协议基于BSD socket和AF_NETLINK地址簇,使⽤32位的端⼝号寻址,每个Netlink协议通常与⼀个或⼀组内核服务/组件相关联,如NETLINK_ROUTE⽤于获取和设置路由与链路信息、NETLINK_KOBJECT_UEVENT⽤于内核向⽤户空间的udev进程发送通知等。

Linux Netlink 基本使用方法

Linux Netlink 基本使用方法

Linux Netlink 基本使用方法1.什么是Netlink什么是Netlink?Netlink是linux提供的用于内核和用户态进程之间的通信方式。

但是注意虽然Netlink主要用于用户空间和内核空间的通信,但是也能用于用户空间的两个进程通信。

只是进程间通信有其他很多方式,一般不用Netlink。

除非需要用到Netlink的广播特性时。

那么Netlink有什么优势呢?一般来说用户空间和内核空间的通信方式有三种:/proc、ioctl、Netlink。

而前两种都是单向的,但是Netlink可以实现双工通信。

Netlink协议基于BSDsocket和AF_NETLINK地址簇(addressfamily),使用32位的端口号寻址(以前称作PID),每个Netlink协议(或称作总线,man手册中则称之为netlinkfamily),通常与一个或一组内核服务/组件相关联,如NETLINK_ROUTE用于获取和设置路由与链路信息、NETLINK_KOBJECT_UEVENT用于内核向用户空间的udev进程发送通知等。

netlink具有以下特点:①支持全双工、异步通信(当然同步也支持)②用户空间可使用标准的BSDsocket接口(但netlink并没有屏蔽掉协议包的构造与解析过程,推荐使用libnl等第三方库)③在内核空间使用专用的内核API接口④支持多播(因此支持“总线”式通信,可实现消息订阅)⑤在内核端可用于进程上下文与中断上下文如何学习Netlink?我觉得最好的方式就是将Netlink和UDPsocket对比学习。

因为他们真的很对地方相似。

AF_NETLINK和AF_INET对应,是一个协议族,而NETLINK_ROUTE、NETLINK_GENERIC这些是协议,对应于UDP。

那么我们主要关注Netlink和UDPsocket之间的不同点,其中最重要的一点就是:使用UDPsocket发送数据包时,用户无需构造UDP数据包的包头,内核协议栈会根据原、目的地址(sockaddr_in)填充头部信息。

netlink用法

netlink用法

Netlink是Linux内核提供的一种进程间通信机制,用于完成内核与用户空间之间的通信。

常用于协议实现、网络管理、虚拟网络等场景。

下面是netlink的常用用法:
创建Socket:使用socket()系统调用来创建一个Netlink 的Socket。

绑定Socket:使用bind()系统调用将Socket与Netlink协议族绑定。

创建Netlink消息:通过Netlink的数据结构来创建Netlink 消息,并填充消息头部和传输数据部分。

发送Netlink消息:使用sendmsg()系统调用来发送Netlink 消息。

接收Netlink消息:使用recvmsg()系统调用来接收Netlink 消息。

解析Netlink消息:使用Netlink的数据结构来解析接收到的Netlink消息,包括消息头部和传输数据部分。

处理Netlink消息:根据不同的消息类型和操作,使用Netlink 的数据结构来处理接收到的Netlink消息。

关闭Socket:使用close()系统调用来关闭Netlink Socket。

总的来说,Netlink是Linux内核中非常重要的IPC机制之一,常被用于内核与用户空间之间的通信,可用于协议实现与管理等多个场景。

基于netlink机制内核空间与用户空间通信的分析

基于netlink机制内核空间与用户空间通信的分析

进程 】
进程 ^ ,
Lnx . iu2 4以后版本 的内核 中 , 几乎全部 的 中断过程 与用 户态进
程 的通信都 是使 用 n tn e ik套接 字实 现 的, l 因而 , 是一个 需要 这 分 析和解决的问题。
1 Lnx内存管理模式 iu
对于 Lnx而言 , iu 用户进程可访 问 4G B的虚 拟线性 内存 空 间 。其 中 0~ B的虚拟 内存地址 是用 户空 间 , 户进程 可 以 3G 用 直接对其进行访 问。3~ B虚拟 内存 地址 是 内核空 间 , 放 4G 存 仅用于 内核访 问的代码 和数据 , 用户对它不能进行操作 。
摘要 : 介绍 了 Lnx操 作 系统的 内核 空间和用 户空间的概念 , 出了基 于 ntn iu 给 el k通信的相关流程 图和 简要 程序说 明。基 于 i
n tn eik的 内核 空间与用户空间的双向通信 , l 可以有效地解决 内核空 间与用户 态进程 间无阻塞通 信的问题 。
关 键 词 :iu ;e ik 内核 空 间 ; 户 空 间 Ln x ntn ; l 用
内核设 计了建 立 在仿 真 ntn okt 的 内核 一用户 通 信协 e iksce 上 l
议, 提供了多个 内核 一用户双 向通 信连接 , 是一套 完整的 内核 肖 息队列的无阻塞支持 。 在 ic d/iu/ e ik h中有类 似 ntn n l el x ntn . u n l el k的 协议 簇 的定 i
DONG Yu MA Xi , n
(c ol f uo ai t nadEetcl nier g Lnh uJ o n nvrt, a zo 30 0 C ia Sho o tm t ao n lc i g e n , azo i t gU i sy L nhu7 0 7 , hn) A zi ra E n i ao ei

Generic Netlink详解

Generic Netlink详解

∙双向传输,异步通信∙用户空间中使用标准socket API∙内核空间中使用专门的API∙支持多播∙可由内核端发起通信∙支持32种协议类型netlink仅支持32种协议类型,这在实际应用中可能并不足够。

因此产生了generic netlink(以下简称为genl)。

generic netlink支持1023个子协议号,弥补了netlink协议类型较少的缺陷。

支持协议号自动分配。

它基于netlink,但是在内核中,generic netlink的接口与netlink并不相同。

1. Generic Netlink框架概述图1表示了Generic Netlink框架。

Kernel socket API向用户空间和内核空间分别提供接口。

Netlink子系统(1)是所有genl通信的基础。

Netlink子系统中收到的所有Generic类型的netlink数据都被送到genl总线(2)上;从内核发出的数据也经由genl总线送至netlink子系统,再打包送至用户空间。

Generic Netlink控制器(4)作为内核的一部分,负责动态地分配genl通道(即genl family id),并管理genl任务。

genl控制器是一个特殊的genl内核用户,它负责监听genl bus上的通信通道。

genl通信建立在一系列的通信通道的基础上,每个genl family对应多个通道,这些通道由genl控制器动态分配。

+---------------------+ +---------------------+| (3) application "A" | | (3) application "B" |+------+--------------+ +--------------+------+| |\ /\ /| |+-------+--------------------------------+-------+| : : |user-space=====+ : (5) Kernel socket API :+================| : : |kernel-space+--------+-------------------------------+-------+| |+-----+-------------------------------+----+| (1) Netlink subsystem |+---------------------+--------------------+|+---------------------+--------------------+| (2) Generic Netlink bus |+--+--------------------------+-------+----+| | |+-------+---------+ | || (4) Controller | / \+-----------------+ / \| |+------------------+--++--+------------------+| (3) kernel user "X" | | (3) kernel user "Y" | +---------------------++---------------------+图1:generic netlink框架2 Generic Netlink相关结构体2.1 genl familyGeneric Netlink是基于客户端-服务端模型的通信机制。

Netlink内核实现分析1

Netlink内核实现分析1

Netlink内核实现分析1Netlink 是⼀种IPC(Inter Process Commumicate)机制,它是⼀种⽤于内核与⽤户空间通信的机制,在⼀般情况下,⽤户态和内核态通信会使⽤传统的Ioctl、sysfs属性⽂件或者procfs属性⽂件,这3种通信⽅式都是同步通信⽅式,由⽤户态主动发起向内核态的通信,内核⽆法主动发起通信。

Netlink是⼀种异步全双⼯的通信⽅式,它⽀持由内核态主动发起通信,内核为Netlink通信提供了⼀组特殊的API接⼝,⽤户态则基于socket API,内核发送的数据会保存在接收进程socket 的接收缓存中,由接收进程处理。

netlink 优点:可以由内核发起,⽤户进程可以使⽤IO复⽤模型⽀持组播,即内核态可以将消息发送给多个接收进程Netlink ⼦系统初始化流程netlink 内核⼦接⼝初始化实在 net/netlink/af_netlink.c中初始化完成static const struct rhashtable_params netlink_rhashtable_params = {.head_offset = offsetof(struct netlink_sock, node),.key_len = netlink_compare_arg_len,.obj_hashfn = netlink_hash,.obj_cmpfn = netlink_compare,.automatic_shrinking = true,};/*这⾥的hash(哈希表)⽤来索引同种协议类型的不同netlink套接字实例,mc_list为多播使⽤的sock散列表,listeners为监听者掩码,groups为协议⽀持的最⼤多播组数量,同时还定义了⼀些函数指针,它们会在内核⾸次创建netlink时被赋值,后续应⽤层创建和绑定socket时调⽤到。

回到初始化函数中,接下来初始化应⽤层使⽤的NETLINK_USERSOCK协议类型的netlink(⽤于应⽤层进程间通信);然后调⽤sock_register向内核注册协议处理函数,即将netlink的socket创建处理函数注册到内核中,如此以后应⽤层创建netlink类型的socket时将会调⽤该协议处理函数,其中*/static int __init netlink_proto_init(void){int i;int err = proto_register(&netlink_proto, 0);if (err != 0)goto out;BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb));//之开辟了MAX_LINKS个na_talbe指针空间nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL);if (!nl_table)goto panic;//分配MAX_LINKS个netlink表结构, nl_table, 每个成员代表⼀种协议类型for (i = 0; i < MAX_LINKS; i++) {if (rhashtable_init(&nl_table[i].hash,&netlink_rhashtable_params) < 0) {rhashtable_destroy(&nl_table[i].hash);kfree(nl_table);goto panic;}}INIT_LIST_HEAD(&netlink_tap_all);netlink_add_usersock_entry();sock_register(&netlink_family_ops);//将netlink socket 创建函数注册到内核中,即创建netlink socket 时回调函数为 netlink_family_ops->create 回调register_pernet_subsys(&netlink_net_ops);/* The netlink device handler may be needed early. */rtnetlink_init();out:return err;panic:panic("netlink_init: Cannot allocate nl_table\n");}core_initcall(netlink_proto_init本初始化函数⾸先向内核注册netlink协议;然后创建并初始化了nl_table表数组,这个表是整个netlink实现的最关键的⼀步,每种协议类型占数组中的⼀项,后续内核中创建的不同种协议类型的netlink都将保存在这个表中.struct netlink_table {struct rhashtable hash;// hash表控制块,内部的hash表记录了已经创建的同种协议类型的所有netlink套接字struct hlist_head mc_list; // 这个hash表头节点⽤于记录同种协议类型下所有阅订了组播功能的套接字struct listeners __rcu *listeners; // 记录了同种协议类型下所有被阅订了的组播消息集合为监听者掩码unsigned int flags;unsigned int groups;// 记录了该协议类型⽀持的最⼤组播数量(通常就是32个)struct mutex *cb_mutex;struct module *module;//函数指针会在内核⾸次创建netlink时被赋值,后续应⽤层创建和绑定socket时调⽤到int (*bind)(struct net *net, int group);void (*unbind)(struct net *net, int group);bool (*compare)(struct net *net, struct sock *sock);int registered;};/*应⽤层创建PF_NETLINK(AF_NETLINK)类型的socket()系统调⽤时将由netlink_create()函数负责处理*/static const struct net_proto_family netlink_family_ops = {.family = PF_NETLINK,.create = netlink_create,.owner = THIS_MODULE, /* for consistency 8) */};Netlink 套接字对于每个类型都会创建⼀个内核的netlink 套接字⽤于和应⽤层通信;以NETLINK_ROUTE为例static int __net_init rtnetlink_net_init(struct net *net){struct sock *sk;struct netlink_kernel_cfg cfg = {.groups = RTNLGRP_MAX,.input = rtnetlink_rcv,.cb_mutex = &rtnl_mutex,.flags = NL_CFG_F_NONROOT_RECV,};sk = netlink_kernel_create(net, NETLINK_ROUTE, &cfg);if (!sk)return -ENOMEM;net->rtnl = sk;return 0;}/*定义了⼀个netlink_kernel_cfg结构体实例,设置groups为RTNLGRP_MAX后指定消息接收处理函数为rtnetlink_rcv,并设置flag为NL_CFG_F_NONROOT_RECV,这表明⾮超级⽤户可以绑定到多播组,但是没有设置NL_CFG_F_NONROOT_SEND,这表明⾮超级⽤户将不能发送组播消息。

内核通信之Netlink源码分析-用户内核通信原理

内核通信之Netlink源码分析-用户内核通信原理

内核通信之Netlink源码分析-⽤户内核通信原理2017-07-05本节从⼀个⼩案例⼊⼿,结合源码分析下通过netlink进⾏内核和⽤户通信的流程。

内核端按照传统CS模式,其实内核端可以作为是服务器端,⽤以接收⽤户的请求并作出处理,但是从netlink本⾝的特性,其更像是⼀个对等实体。

双⽅都可以进⾏主动数据的传递。

内核中⾸先调⽤netlink_kernel_create函数创建⼀个sock结构,其实这⾥仅仅是返回⼀个sock结构,⽽其中创建了相关的socket,netlink_sock,inode 等。

⽼版本的函数参数都是写在netlink_kernel_create函数⾥的,现在把部分参数抽离到⼀个netlink_kernel_cfg结构中,其中我们只关⼼接收数据的处理函数.input。

⾸个参数表⽰⽹络命名空间,⼀般取init_net,NETLINK_TEST是我们⾃定义的协议类型,netlink⽀持32个协议0-31,其实就是协商好的⼀个数字,⽤来⽤户层和内核层的通信。

第三个就是我们的配置结构。

函数内部⾸先创建了socket,然后创建了sock,并在socket和sock间建⽴关联,默认创建sock是在全局的命名空间init_net下,所以还需要修改到参数中的net,不过⼀般我们也正是选择全局的。

然后需要设置接收函数到netlink_sock 中的netlink_rcv字段。

最后需要把sock加⼊到全局管理结构nl_table中。

函数⼤致功能如此,后⾯我们再详细讨论。

⽬前sock已经注册上,如何处理接收到的数据呢?看下我们实现的简单的接收函数rece_msg,Netlink基于socket,所以其数据是通过套接字缓冲区sk_buff管理的。

从skb中获取信息长度,该长度是包含了nlmsghdr的长度加上数据,后⾯为了⽅便直接读取的100字节,实际上应该让获取到的长度将去nlmsghdr的长度。

Netlink编程-数据结构

Netlink编程-数据结构

Netlink编程-数据结构内核态与用户态进行数据交互的方法很多,分为用户程序主动发起的消息交交互和内核主动发起的信息交互。

通常我们所熟知的系统调用、对/proc进行读写操作、mmap和编写驱动程序等都属于前者,而由内核主动发起的信息交互方法比较少,最典型的方法为内核发送信号给当前进程。

上述这些方法都是单向通信的,也就是说要么是用户态进程主动发起数据交互会话,要么是内核主动发起会话。

有没有一种可以在用户态和内核态进行双向数据交互的方法呢?Netlink是一种在内核态和用户态可以进行双向数据交互的通信机制。

在用户态,我们可以将netlink看作是一种特殊的socket,因此通过socket接口来就可以直接使用netlink;在内核态,则需要通过一组特殊的内核接口编写内核模块。

如果初次编写netlink程序,可能会对它所涉及的数据结构感到困惑,本文将简单介绍一下netlink编程中遇到的基本数据结构。

struct msghdr如果使用sendmsg()发送数据,那么必须使用msghdr结构,该结构内部封装了本次发送数据的一些参数:1 struct msghdr {2 void *msg_name; /* optionaladdress */3 socklen_t msg_namelen; /* size of address */4 struct iovec *msg_iov; /* scatter/gather array*/5 size_t msg_iovlen; /* # elements inmsg_iov */6 void *msg_control; /* ancillary data,see below */7 size_t msg_controllen; /* ancillary databuffer len */8 int msg_flags; /* flags onreceived message */9 };netlink提供的是一种基于数据报的通信服务,因此与UDP通信协议类似,必须通过msg_name指明目的套接字地址结构,而msg_namelen则指明该地址结构的长度。

Netlink设计详细资料汇编

Netlink设计详细资料汇编

Netlink设计详细资料汇编1 引言1.1编写目的详细描述etrinf接口各功能块的实现方法。

此文档是《etrainf概要设计》的输出,是软件代码的输入文档。

1.2背景etrainf用于内核态与用户态的通道,为了提高通信效率,简化设计,模块采用了netlink 方式。

1.3定义参见概要设计1.4设计依据《D8135软件概要设计说明书》V0.2 3.2.2.7 EtraInf模块2软件系统结构2.1功能需求参见《终端基础平台软件需求规格说明书》V0.1 3.1.7Etrainf2.2etrainf模块提供的接口函数int EtraInfSend(char *pBuf, int iByteSize, unsigned short eType);int EtraInfSendMsg(MSG_NODE *pMsg);3 数据结构3.1公有数据结构typedef enum{CONFLICT_PARA = 5,//RET_REG_CMDFAILED = 6}ETRAINF_KERN_ERR_CODE_e;//etrainf无法统计的出错码typedef enum{ETRAINF_MSG = 0, /*通过netlink发送消息*/ETRAINF_OAM = 1, /*............oam*/ETRAINF_DATA = 2, /*............语言数据*/ETRAINF_LOG = 3, /*............log*/ETRAINF_INIT_MSG = 4,ETRAINF_INIT_DATA = 5,ETRAINF_OAM_TO_DSP= 6/*直接发送给dsp的oam*/}ETRAINF_MSGTYPE_e;#define NETLINK_ETRAINF 17 //neilink协议值#define ETRAINF_MAX_PAYLOAD 2048 //netlink最大负载3.1.1用户态#define ETRAINF_SEND_STACK_SIZE 0x1000 //用户态send任务堆栈大小#define ETRAINF_RECV_STACK_SIZE 0x1000 //用户态recv任务堆栈大小#define ETRAINF_SEND_PRIORITY 200 //用户态send任务优先级#define ETRAINF_RECV_PRIORITY 201 //用户态recv任务优先级#define EF_MAX_DATA_NODE 1024 //模块提供同时处理的最大数据节点#define EF_MAX_TMP_BUFF 512 //需要etrainf提供零时数据存储区的最大数据节点3.1.2内核态无3.2私有数据结构typedef struct{char *pname;//统计项名称int iValue;//相应次数}ETRAINF_STAT_t;//统计计数数据结构typedef struct{struct nlmsghdr tNlMsgHdr;char pDataBuf[0];}ETRAINF_EMBED_COMM_t;typedef struct{char *pName;//通道名称int iSockfd;//通道sock fdint iPid;//该值应该另外赋值的,socket理论上根据pid进行创建LIST sendList;//通道在用户态的发送队列int (*HandleRecv)(void *ptNlMsg);//通道的接收回调函数struct nlmsghdr *(*GetNlhdr)(char *buff, int ihdrSize);//赋值必须把FreeNode赋上void (*FreeNode)(void *buff);//释放该通道上数据节点函数}ETRAINF_CHANN_ATTR_t;3.2.1用户态3.2.2内核态4程序设计说明4.1.1 int EtraInfInit(void)4.1.1.1程序描述在平台初始化的时候,调用该函数初始化etrainf模块4.1.1.2功能初始化etrainf所需所有资源,包括命令行相关4.1.1.3性能无4.1.1.4 输入无4.1.1.5输出无4.1.1.6返回成功ETOK,失败ETERROR or RET_REG_CMDFAILED4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1注册命令行regEtraInfUsrCmd()2.初始化各种锁CreateSem()3.初始化发送节点etraInfInitNodePool()4.初始化零时缓存节点etraInfInitTmpBuffPool()5根据通道创建相应的socket etraInfCreateSocket()6.初始化各通道发送队列lstInit7.创建发送任务CreateCommonThread8创建接收任务CreateCommonThread4.1.1.8.2内核态1.注册命令行regEtraInfUsrCmd()2.创建sock并注册接收回调函数 netlink_kernel_create(…EtraInfRecv…)3.注册sysfs文件系统 etraInfRegSysfs()4.1.2 int regEtraInfUsrCmd(void)4.1.2.1程序描述注册模块相应命令行4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态调用平台命令行注册接口注册4.1.1.8.2内核态调用平台命令行注册接口注册4.1.2 EINT32 etraInfInitNodePool()4.1.2.1程序描述初始化用户态数据发送节点4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.申请sizeof(ETRAINF_NODE_t) * EF_MAX_DATA_NODE大小空间2.将申请到的内存分块并连入链表4.1.1.8.2内核态无该函数4.1.2 EINT32 etraInfInitTmpBuffPool()4.1.2.1程序描述初始化用户态零时缓存区节点4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.申请sizeof(ETRAINF_TMP_BUFF_t) * EF_MAX_TMP_BUFF大小空间2.将申请到的内存分块并连入链表4.1.1.8.2内核态无该函数4.1.2 EINT32 etraInfCreateSocket(int iPid)4.1.2.1程序描述根据传入的pid创建相应socket4.1.2.2功能无4.1.2.3性能无4.1.2.4输入通道号,也即pid4.1.2.5输出无4.1.1.6返回成功socketfd,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.根据传入通道号判断是否有相同pid注册过2.若注册过则执行第3步否则跳到第7步3.遍历所有注册通道并找到第一个注册该通道号通道,记录其接收处理函数与socketfd4.判断接收处理函数是否与本次注册一样,若一样则执行第5步,否则跳转至第6步5.将本次找到的socketfd返回6.遍历每个通道,将通道号与本次注册一样的接收处理函数全部指向handleConflictChannId函数,跳转至第5步7.创建socket8.bind相应地址9.返回socketfd4.1.1.8.2内核态无该函数4.1.2 int handleConflictChannId(void *iSkfd)4.1.2.1程序描述通道创建冲突后的处理函数4.1.2.2功能打印提示通道初始化时出错4.1.2.3性能无4.1.2.4输入void *iSkfd4.1.2.5输出无4.1.1.6返回ETOK4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态打印socket通道创建冲突统计信息更新4.1.1.8.2内核态无该函数4.1.2 void etraInfRegSysfs(void)4.1.2.1程序描述注册sysfs文件系统4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回无4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态无该函数4.1.1.8.2内核态调用内核接口注册相应的sysfs4.1.2 int EtraInfSend(char *pBuf, int iByteSize, unsigned short eType) 4.1.2.1程序描述通用发送接口4.1.2.2功能无4.1.2.3性能无4.1.2.4输入pBuf 待发送数据指针iByteSize待发送数据字节大小eType 数据类型4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.根据数据类型转成通道类型2.传入数据合法性检查3.获取发送数据节点EtraInfGetNode()4.判断是否需要拷贝发送数据放到零时缓存区,若不需要则执行第5步否则跳转至第6步5.根据传入数据找到预留给nl头节点指针,跳转至第7步6.申请零时缓存节点,并拷贝相应数据EtraInfGetTmpBuff()7.初始化相应数据结构,放入相应发送队列,释放发送信号量4.1.1.8.2内核态1.传入数据合法性检查2.申请sk_buff3.填充相应数据4.调用内核接口发送数据4.1.2 ETRAINF_NODE_t *EtraInfGetNode(void)4.1.2.1程序描述分配数据节点4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回ETRAINF_NODE_t *4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态从数据节点list中get节点4.1.1.8.2内核态无该函数4.1.2 ETRAINF_TMP_BUFF_t *EtraInfGetTmpBuff(void) 4.1.2.1程序描述分配临时数据节点4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回ETRAINF_TMP_BUFF_t *4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态从零时数据节点list中get节点4.1.1.8.2内核态无该函数4.1.2 void *EtraInfSendThread(void *pVoid)4.1.2.1程序描述用户态数据发送任务4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回无4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.等待发送信号量2.获取发送数据节点EtraInfGetSendData()3.发送相应数据4.释放请求数据缓冲区ptDataNode->pFreeExternMMFun()5.释放数据节点缓冲区EtraInfPutNode()4.1.1.8.2内核态无该函数4.1.2 ETRAINF_NODE_t *EtraInfGetSendData()4.1.2.1程序描述从发送队列中获得发送数据节点4.1.2.2功能按优先级遍历各个通道的发送数据4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回ETRAINF_NODE_t *4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态按优先级遍历各个通道是否有数据发送,如有则立即返回,若无则继续往下一条通道查找4.1.1.8.2内核态无该函数4.1.2 void EtraInfPutNode(ETRAINF_NODE_t *ptDataNode)4.1.2.1程序描述将数据节点放回list4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回无4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态将数据放回节点list4.1.1.8.2内核态无该函数4.1.2 void EtraInfPutTmpBuff(ETRAINF_TMP_BUFF_t *ptTmpBuff) 4.1.2.1程序描述将零时缓冲区放回list4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回无4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态将零时缓存节点放回list4.1.1.8.2内核态无该函数4.1.2 int EtraInfSendMsg(MSG_NODE *pMsg)4.1.2.1程序描述etrainf提供给msg模块使用接口4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.计算实际发送数据长度2.获取msg有效数据指针3.调用EtraInfSend4.1.1.8.2内核态1.计算实际发送数据长度2.得到app_msg出去nl的指针3.调用EtraInfSend4.1.2 void EtraInfRecv(struct sk_buff *pSkb) 4.1.2.1程序描述内核态接收数据回调函数4.1.2.2功能无4.1.2.3性能无4.1.2.4输入*pSkb4.1.2.5输出无4.1.1.6返回无4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态无该函数4.1.1.8.2内核态1.获取sk_buff的nl指针2.根据收到nl数据的头指针判断数据类型3.调用相应的接收函数4.1.2 int EtraInfRecvMsg(void *pnl)4.1.2.1程序描述内核态处理收到msg消息4.1.2.2功能无4.1.2.3性能无4.1.2.4输入*pnl4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.getMsgNode()2.调用系统调用recvfrom接收数据,并传入消息的app_msg结构3.sendmsg4.1.1.8.2内核态1.getMsgNode,并初始化相应值2.将nl收到的app_msg拷贝到申请的消息节点中3.sendmsg()4.1.2 int EtraInfRecvOAM(void *pnl)4.1.2.1程序描述处理收到的oam数据类型4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.用栈空间数组调用recvfrom接收数据2.调用相应的处理函数4.1.1.8.2内核态1.进一步判断数据类型是否需要直接发送给dsp2.根据判断结果调用相应处理函数4.1.2 int EtraInfRecvDate(void *pnl) 4.1.2.1程序描述处理收到data数据类型4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.用栈空间数组调用recvfrom接收数据2.调用相应的处理函数4.1.1.8.2内核态调用发送到dsp接口函数4.1.2 int EtraInfRecvLog(void *pnl) 4.1.2.1程序描述处理收到log数据类型4.1.2.2功能无4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回成功ETOK,失败ETERROR4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.用栈空间数组调用recvfrom接收数据2.调用相应的处理函数4.1.1.8.2内核态收到不可能的数据,打印并更新统计信息4.1.2 void *EtraInfRecvThread(void *pVoid)4.1.2.1程序描述用户态数据接收任务4.1.2.2功能用于接收从内核态上发的nl数据4.1.2.3性能无4.1.2.4输入无4.1.2.5输出无4.1.1.6返回无4.1.1.7算法无4.1.1.8流程4.1.1.8.1用户态1.使用select判断是否有数据上来,如有则执行第2步,否则循环2.根据优先级遍历相应通道是否有数据到达,并调用相应接收函数4.1.1.8.2内核态无该函数.。

内核通信之Netlink源码分析-基础架构

内核通信之Netlink源码分析-基础架构

内核通信之Netlink源码分析-基础架构2017-07-04netlink是⼀种基于⽹络的通信机制,⼀般⽤于内核内部或者内核与⽤户层之间的通信。

其有⼀个明显的特点就是异步性,通信的双⽅不要求同时在线,也就不⽤阻塞等待。

NetLink按照数据包的格式发送/接收消息,提供双向通信,和其他内核与⽤户层通信机制相⽐,NetLink有其特有的优势:任何⼀⽅不需要轮训,如果通过⽂件传递状态信息,则需要不断的检查是否有新消息到达。

系统调⽤和ioctl均可以从⽤户层向内核传递消息,但⽐简单的Netlink链接难于实现,另外,NetLink是系统提供的机制,不会和任何模块其冲突,兼容性好。

使⽤NetLink可以让内核主动的向⽤户层发消息,此时内核扮演的就是⼀个逻辑⽤户;⽽ioctl和系统调⽤、/proc均只能由⽤户层发起请求,让内核去被动响应。

Netlink不仅⽀持单播,也⽀持多播即向多个进程发送消息。

从逻辑上来讲,NetLink应该处于传输层,因此其同样需要特定的协议。

对于NetLink就是Netlink协议,内核中有netlink_family_ops,在⽤户层创建netlink类型的socket的时候最终会调⽤到netlink_family_ops注册的create函数static const struct net_proto_family netlink_family_ops = {.family = PF_NETLINK,.create = netlink_create,.owner = THIS_MODULE, /* for consistency 8) */};每种协议都需要⼀组协议处理函数,针对Netlink有netlink_opsstatic const struct proto_ops netlink_ops = {.family = PF_NETLINK,.owner = THIS_MODULE,.release = netlink_release,.bind = netlink_bind,.connect = netlink_connect,.socketpair = sock_no_socketpair,.accept = sock_no_accept,.getname = netlink_getname,.poll = netlink_poll,.ioctl = sock_no_ioctl,.listen = sock_no_listen,.shutdown = sock_no_shutdown,.setsockopt = netlink_setsockopt,.getsockopt = netlink_getsockopt,.sendmsg = netlink_sendmsg,.recvmsg = netlink_recvmsg,.mmap = netlink_mmap,.sendpage = sock_no_sendpage,};我们重点关注netlink_sendmsg和netlink_recvmsg,这是netlink发送和接收数据的处理函数。

linuxnetlink详解3-netlink总结

linuxnetlink详解3-netlink总结

linuxnetlink详解3-netlink总结1 netlink初始化2 内核netlink创建3 应⽤层netlink创建4 应⽤层向内核发送消息5 应⽤层接收内核消息6 内核向应⽤层发送消息7 内核和应⽤层netlink通信实例7.1 应⽤层代码实例1/*应⽤层代码*/2 #include <sys/stat.h>3 #include <unistd.h>4 #include <stdio.h>5 #include <stdlib.h>6 #include <sys/socket.h>7 #include <sys/types.h>8 #include <string.h>9 #include <asm/types.h>10 #include <linux/netlink.h>11 #include <linux/socket.h>1213#define MAX_PAYLOAD 1024 /* maximum payload size*/14struct sockaddr_nl src_addr, dest_addr;15struct nlmsghdr *nlh = NULL;16struct iovec iov;17int sock_fd;18struct msghdr msg;1920int main(int argc, char* argv[])21 {22 sock_fd = socket(PF_NETLINK, SOCK_RAW, 21);23 memset(&msg, 0, sizeof(msg));24 memset(&src_addr, 0, sizeof(src_addr));25 src_addr.nl_family = AF_NETLINK;26 src_addr.nl_pid = getpid(); /* self pid */27 src_addr.nl_groups = 0; /* not in mcast groups */28 bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));29 memset(&dest_addr, 0, sizeof(dest_addr));30 dest_addr.nl_family = AF_NETLINK;31 dest_addr.nl_pid = 0; /* For Linux Kernel */32 dest_addr.nl_groups = 0; /* unicast */3334 nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); 35/* Fill the netlink message header */36 nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);37 nlh->nlmsg_pid = getpid(); /* self pid */38 nlh->nlmsg_flags = 0;39/* Fill in the netlink message payload */40 strcpy(NLMSG_DATA(nlh), "Hello you!");4142 iov.iov_base = (void *)nlh;43 iov.iov_len = nlh->nlmsg_len;44 msg.msg_name = (void *)&dest_addr;45 msg.msg_namelen = sizeof(dest_addr);46 msg.msg_iov = &iov;47 msg.msg_iovlen = 1;4849 printf(" Sending message. ...\n");50 sendmsg(sock_fd, &msg, 0);//向内核发送消息5152/* Read message from kernel */53 memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));54 printf(" Waiting message. ...\n");55 recvmsg(sock_fd, &msg, 0);//接收内核的消息56 printf(" Received message payload: %s\n",NLMSG_DATA(nlh));5758/* Close Netlink Socket */59 close(sock_fd);60 }7.2 内核层代码实例1/*内核层代码*/23 #include <linux/kernel.h>4 #include <linux/module.h>5 #include <linux/types.h>6 #include <linux/sched.h>7 #include <net/sock.h>8 #include <net/netlink.h>910#define NETLINK_TEST 211112struct sock *nl_sk = NULL;13 EXPORT_SYMBOL_GPL(nl_sk);1415void nl_send(struct sk_buff *__skb)16 {17struct sk_buff *skb;18struct nlmsghdr *nlh;19 u32 pid;20int rc;21int len = NLMSG_SPACE(1200);22char str[100];2324 printk("net_link: data is ready to read.\n");25 skb = skb_get(__skb);2627if (skb->len >= NLMSG_SPACE(0)) {28 nlh = nlmsg_hdr(skb);//接收应⽤层的消息头29 printk("nl_send: recv %s.\n", (char *)NLMSG_DATA(nlh));//NLMSG_DATA(nlh)接收应⽤层消息数据30 memcpy(str,NLMSG_DATA(nlh), sizeof(str));31 pid = nlh->nlmsg_pid; /*pid of sending process */32 printk("nl_send: pid is %d\n", pid);33 kfree_skb(skb);3435 skb = alloc_skb(len, GFP_ATOMIC);36if (!skb){37 printk(KERN_ERR "nl_send: allocate failed.\n");38return;39 }40 nlh = nlmsg_put(skb,0,0,0,1200,0);41 NETLINK_CB(skb).pid = 0; /* from kernel */4243 memcpy(NLMSG_DATA(nlh), str, sizeof(str));44 printk("nl_send: going to send.\n");45 rc = netlink_unicast(nl_sk, skb, pid, MSG_DONTWAIT);//向应⽤层发送消息46if (rc < 0) {47 printk(KERN_ERR "nl_send: can not unicast skb (%d)\n", rc);48 }49 printk("nl_send: send is ok.\n");50 }51return;52 }5354static int kernel_netlink_test(void) {55 nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0, nl_send, NULL, THIS_MODULE);//创建netlink socket 5657if (!nl_sk) {58 printk(KERN_ERR "kernel_netlink_test: Cannot create netlink socket.\n");59return -EIO;60 }61 printk("kernel_netlink_test: create socket ok.\n");62return0;63 }6465int init_module()66 {67 kernel_netlink_test();68return0;69 }70void cleanup_module( )71 {72if (nl_sk != NULL){73 sock_release(nl_sk->sk_socket);74 }75 printk("kernel_netlink_test: remove ok.\n");76 }77 MODULE_LICENSE("GPL");78 MODULE_AUTHOR("action_er");待测试。

Linux中内核通信Netlink机制

Linux中内核通信Netlink机制

Linux中与内核通信的Netlink机制Netlink在2.6版本的内核中变化也是很大的,在最新的2.6.37内核中,其定义已经改成下面这种形式,传递的参数已经达到6个。

其中第一个参数和mutex参数都是最新添加的。

Mutex 也可以为空。

这里主要是关于内核空间中的netlink函数的使用。

extern struct sock *netlink_kernel_create(struct net *net,int unit,unsigned int groups,void (*input)(struct sk_buff *skb),struct mutex *cb_mutex,struct module *module)。

struct net是一个网络名字空间namespace,在不同的名字空间里面可以有自己的转发信息库,有自己的一套net_device等等。

默认情况下都是使用init_net这个全局变量,下面是内核中调用netlink_kernel_create()函数的一个示例。

在内核中,audit_sock = netlink_kernel_create(&init_net, NETLINK_AUDIT, 0,audit_receive, NULL, THIS_MODULE)。

模块调用函数netlink_unicast 来发送单播消息:int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock)参数ssk为函数netlink_kernel_create()返回的socket,参数skb存放消息,它的data字段指向要发送的netlink消息结构,而skb的控制块保存了消息的地址信息,前面的宏NETLINK_CB(skb)就用于方便设置该控制块,参数pid为接收消息进程的pid,参数nonblock 表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回,而如果为0,该函数在没有接收缓存可利用定时睡眠。

netlink的使用方法

netlink的使用方法

《netlink的使用方法》在Linux 2.4 版以后版本的内核中,几乎全部的中断过程与用户态进程的通信都是使用netlink 套接字实现的,著名的内核包过滤框架Netfilter 在与用户空间的通读,也在最新版本中改变为netlink,无疑,它将是Linux 用户态与内核态交流的主要方法之一。

它的通信依据是一个对应于进程的标识,一般定为该进程的ID。

当通信的一端处于中断过程时,该标识为0。

当使用netlink 套接字进行通信,通信的双方都是用户态进程,则使用方法类似于消息队列。

netlink 套接字的最大特点是对中断过程的支持,它在内核空间接收用户空间数据时不再需要用户自行启动一个内核线程,而是通过另一个软中断调用用户事先指定的接收函数。

这样就可以保证数据接收的实时性。

当netlink 套接字用于内核空间与用户空间的通信时,在用户空间的创建方法和一般套接字使用类似,但内核空间的创建方法则不同。

用户空间用户态应用使用标准的socket 与内核通讯,标准的socket API 的函数,socket(), bind(),sendmsg(), recvmsg() 和close()很容易地应用到netlink socket。

为了创建一个netlink socket,用户需要使用如下参数调用socket():socket(AF_NETLINK, SOCK_RAW, netlink_type)netlink 对应的协议簇是AF_NETLINK,第二个参数必须是SOCK_RAW 或SOCK_DGRAM,第三个参数指定netlink 协议类型,它可以是一个自定义的类型,也可以使用内核预定义的类型:#define NETLINK_ROUTE 0 /* Routing/device hook */#define NETLINK_W1 1 /* 1-wire subsystem */#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */#define NETLINK_FIREWALL 3 /* Firewalling hook */#define NETLINK_INET_DIAG 4 /* INET socket monitoring */#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */#define NETLINK_XFRM 6 /* ipsec */#define NETLINK_SELINUX 7 /* SELinux event notifications */#define NETLINK_ISCSI 8 /* Open-iSCSI */#define NETLINK_AUDIT 9 /* auditing */#define NETLINK_FIB_LOOKUP 10#define NETLINK_CONNECTOR 11#define NETLINK_NETFILTER 12 /* netfilter subsystem */#define NETLINK_IP6_FW 13#define NETLINK_DNRTMSG 14 /* DECnet routing messages */#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */#define NETLINK_GENERIC 16同样地,socket 函数返回的套接字,可以交给bind等函数调用:static int skfd;skfd = socket(PF_NETLINK, SOCK_RAW, NL_IMP2);if(skfd < 0){printf("can not create a netlink socket\n");exit(0);}bind 函数需要绑定协议地址,netlink 的socket 地址使用struct sockaddr_nl 结构描述:struct sockaddr_nl{sa_family_t nl_family;unsigned short nl_pad;__u32 nl_pid;__u32 nl_groups;};成员nl_family 为协议簇AF_NETLINK,成员nl_pad 当前没有使用,因此要总是设置为0,成员nl_pid 为接收或发送消息的进程的ID,如果希望内核处理消息或多播消息,就把该字段设置为0,否则设置为处理消息的进程ID。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。

E-mail: wwwlkk@来源: /?business&aid=6&un=wwwlkk#7netlink实现分析(1)网络file对象。

1(2)netlink网络file对象。

3(3)netlink消息接收端。

5(3.1)内核路径注册netlink接收端。

6(3.2)用户进程注册netlink接收端。

6(3.3)内核netlink接收端接收消息。

6(3.4)用户进程netlink接收端接收消息。

6(4)通信效率分析。

7(5)实现零拷贝的两个理论方案。

7(1)网络file对象当网络双方的通信线路建立好之后,双发就可以开始互相传递数据,可以使用write()和read()传递数据。

可见网络通信也同样使用了文件系统的架构,这里的file对象是比较特殊的,结构如图1所示:图1 网络file对象结构其中static const struct file_operations socket_file_ops = {.owner = THIS_MODULE,.llseek = no_llseek,.aio_read = sock_aio_read,对应read().aio_write = sock_aio_write,对应write().poll = sock_poll,.unlocked_ioctl = sock_ioctl,.mmap = sock_mmap,.open = sock_no_open, /* special open code to disallow open via /proc */.release = sock_close,.fasync = sock_fasync,.sendpage = sock_sendpage,.splice_write = generic_splice_sendpage,.splice_read = sock_splice_read,};说明:如果file->f_op->write为空,则会调用file->f_op-> aio_write;file->f_op->read为空,则会调用file->f_op-> aio_read从sock_aio_write()开始的函数调用流程如下:sock_aio_write()→do_sock_write()→__sock_sendmsg()→sock->ops->sendmsg(iocb, sock, msg, size);从sock_aio_read()开始的函数调用流程如下:sock_aio_read()→do_sock_read()→__sock_recvmsg()→__sock_recvmsg_nosec()→sock->ops->recvmsg(iocb, sock, msg, size, flags);可见发送和接受过程最终都是调用操作函数集sock->ops,其结构如下:struct proto_ops {int family;struct module *owner;int (*release) (struct socket *sock);int (*bind) (struct socket *sock, struct sockaddr *myaddr, int sockaddr_len);int (*connect)(struct socket *sock, struct sockaddr *vaddr,int sockaddr_len, int flags);int (*socketpair)(struct socket *sock1,struct socket *sock2);int (*accept) (struct socket *sock,struct socket *newsock, int flags);int (*getname) (struct socket *sock, struct sockaddr *addr, int *sockaddr_len, int peer);unsigned int (*poll) (struct file *file, struct socket *sock, struct poll_table_struct *wait);int (*ioctl) (struct socket *sock, unsigned int cmd, unsigned long arg);int (*compat_ioctl) (struct socket *sock, unsigned int cmd, unsigned long arg);int (*listen) (struct socket *sock, int len);int (*shutdown) (struct socket *sock, int flags);int(*setsockopt)(struct socket *sock, int level,int optname, char __user *optval, unsigned int optlen);int(*getsockopt)(struct socket *sock, int level,int optname, char __user *optval, int __user *optlen); int(*compat_setsockopt)(struct socket *sock, int level,int optname, char *optval, unsigned int optlen);int(*compat_getsockopt)(struct socket *sock, int level,int optname, char *optval, int *optlen);int (*sendmsg)(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len);int(*recvmsg)(struct kiocb *iocb, struct socket *sock,struct msghdr *m, size_t total_len, int flags);int (*mmap)(struct file *file, struct socket *sock, struct vm_area_struct * vma);ssize_t (*sendpage) (struct socket *sock, struct page *page, int offset, size_t size, int flags);ssize_t(*splice_read)(struct socket *sock,loff_t *ppos,struct pipe_inode_info*pipe,size_t len, unsigned int flags);};应用程序的bind(),listen(),accept(),connect(),read(),write(),close()都最终调用struct proto_ops 内的函数。

(2)netlink网络file对象当网络应用程序调用socket()时,将会建立如图1所示的file结构。

例如:socket(AF_NETLINK, SOCK_RAW,NETLINK_GENERIC);函数调用流程如下:SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)→sys_socket() [SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)] →sock_create()→__sock_create()→pf = rcu_dereference(net_families[family])→err = pf->create(net, sock, protocol, kern);→sock_map_fd()在static int __init netlink_proto_init(void)中可以看到netlink协议的注册函数:sock_register(&netlink_family_ops);其中static const struct net_proto_family netlink_family_ops = {.family = PF_NETLINK,.create = netlink_create,.owner = THIS_MODULE, /* for consistency 8) */};现在可以知道上边的pf->create(net, sock, protocol, kern);是调用netlink_create()生成的file对象结构如图2所示:图2 netlink的file对象结构其中static const struct proto_ops netlink_ops = {.family = PF_NETLINK,.owner = THIS_MODULE,.release = netlink_release,.bind = netlink_bind,.connect = netlink_connect,.socketpair = s ock_no_socketpair,.accept = sock_no_accept,.getname = netlink_getname,.poll = datagram_poll,.ioctl = sock_no_ioctl,.listen = sock_no_listen,.shutdown = sock_no_shutdown,.setsockopt = netlink_setsockopt,.getsockopt = netlink_getsockopt,.sendmsg = netlink_sendmsg,.recvmsg = netlink_recvmsg,.mmap = sock_no_mmap,.sendpage = sock_no_sendpage,};struct sock对象是包含在netlink_sock中。

相关文档
最新文档