libnl库应用详解(一)

  libnl库提供了一套应用于Linux系统基于Netlink协议通信的API接口。从本质上看,Netlink其实是一种典型的IPC机制,只不过此IPC主要是介于用户空间与内核空间之间的通信,而非传统意义上用户空间进程之间的通信。Netlink是设计出来替换ioctl机制,就目前的使用情况,这一点显然还没有完全达到。

构成

  libnl在设计上被分割为若干个小型库(small libraries),应用程序在链接时可以择库链接,无需将所有库链接到应用程序中。

  • libnl:libnl的核心库,构建Netlink通信的基础,提供套接字操作、消息构建/解析、收发报文等操作
  • libnl-route:提供NETLINK_ROUTE家族的API接口库,包括网络设备、路由功能、IP地址、邻居功能等操作
  • libnl-genl:通用Netlink操作
  • libnl-nf:NetFilter以及接口监控相关的Netlink操作
    libnl库构成及基本特性

使用方法

头文件

libnl提供的主要头文件为<netlink/netlink.h>,此外还提供了一些其他头文件,可以视应用程序的需要酌情增删。

#include <netlink/netlink.h>

#include <netlink/cache.h>
#include <netlink/route/link.h>
#include <netlink/route/addr.h>

链接

可以在gcc中直接链接libnl库

$ gcc myprogram.c -o myprogram $(pkgconfig --cflags --libs libnl-3.0)
$ #或采取直接链接方式
& gcc -Wall -Wextra -pedantic listif.c -o lsif -lnl-3 -lnl-route-3 -isystem /usr/include/libnl3

Netlink协议

  Netlink 协议是基于套接字的进程间通信(IPC)机制,它可用于用户空间进程和内核之间或者用户空间进程之间的通信。Netlink协议基于BSD套接字并使用AF_NETLINK地址簇。每一个Netlink协议都有自己的协议号(比如:NETLINK_ROUTE、NETLINK_NETFILTER等)。它的寻址方案是基于 32 位的端口号(之前被称为 PID),此端口号用于唯一地标识每一个对等通信节点。

寻址

  Netlink 地址(端口)由一个 32 位的整数组成。端口(port)零保留给内核使用,表示每个Netlink协议簇中内核部分的套接字,其他的端口则通常指的是用户空间的套接字。
  注意: 最初通常使用进程标识符(PID)作为本地端口号,但这种方式随着线程化Netlink应用程序的引入而失效,因为这类进程需要多个套接字。为解决此项冲突,libnl以进程标识符为基数再加上一个偏移量来生成唯一的端口号,此方式可以让一个进程使用多个套接字。出于向后兼容方面的考虑,第一个套接字还是以进程标识符作为端口号。

Netlink寻址

  上图中用户空间有三个应用程序,对应有5个套接字;而内核空间则创建了2个套接字。同时,此图也展示了Netlink的常见应用场景:

  • 用户空间的进程和内核的通信
  • 用户空间内进程之间的通信
  • 侦听内核的多播通知

应用场景

用户空间进程和内核的通信

  Netlink最常见的应用场景就是用户空间应用程序发送请求给内核,比如设置/读取接口的IP地址,然后接受并处理内核返回的信息,这个回复信息要么是请求出错的信息,要么就是请求成功的通知信息。


用户空间和内核空间通信

用户空间进程之间的通信

  Netlink也可以直接作为用户空间应用程序之间的进程间通信机制,但这种方式并不常见,通常会代之以unix域套接字。这种通信并不限制在两个对等通信节点之间,任意一个节点都可以和其他的对等点进行通信。此外因为Netlink支持多播,一条消息可以由多个节点同时接收到。
  注意:为了让套接字对通信双方可见,这两个套接字必须在同一个Netlink协议簇下创建。


用户空间之间通信

侦听内核的多播通知信息

  此类Netlink通信是一种非常常见的应用方式,此方式可以让用户空间那些需要处理特定内核事件的的守护进程侦听内核反馈的消息/事件。这些应用程序进程通常会订阅内核使用的某个多播组,内核则在某些事件发生的时候通过它来通知订阅该组播组的进程。


侦听内核多播通知消息

  相对于直接寻址来说,多播(组播)寻址是一个更好的方式,因为它有更高的灵活性,可以在无需通知内核的情况下随时与用户空间应用组件交换信息。

消息格式

  Netlink协议通常是基于消息的,消息则通常是由Netlink消息头部(struct nlmsghdr)加上有效载荷组成。虽然有效载荷可以由任何数据组成,但是它通常的格式是一 个固定大小的协议相关头部后面紧跟一系列的属性。


Netlink消息头组成
  • 总长度(32 位):消息包括 netlink 消息头部在内的总字节数
  • 消息类型(16 位):消息类型指明了消息的有效载荷的类型。netlink 协议定义了多个标准的消息类型。每个协 议簇都可能定义了额外的消息类型。
  • 消息标志(16 位):消息标志可以用来更改消息类型的行为。
  • 序列号(32 位):序列号的使用是可选的,它可以用来引用前一条消息。比如一条错误消息中可以引用导致错 误的那条请求消息。
  • 端口号:端口号指明了这条消息需要发往哪个对等节点。如果没有指定端口号,那么这条消息会被投 递给同一个协议簇中第一个匹配的内核端套接字。

消息类型

  Netlink 在请求消息(requests)、通知消息(notifications)和应答消息(replies)的 处理上是有区别的。请求消息设有 NLM_F_REQUEST 标志位,它用来向接收方请求某种响应 。一般来说请求消息都是从用户空间发送到内核的。虽然不是强制规定,但每次发送的请求 消息序列号都应该是上一个序列号加一。
  由于请求自身的特性,接收方在收到请求消息之后可能会发送另一条 netlink 消息来响应 这个请求。应答消息的序列号必须和它响应的那条请求消息的序列号一致。
  通知消息则没有那么严谨,它不需要应答,所以序列号通常是被设置成 0 的。


消息类型

消息的类型主要是由消息头部中 16 位的消息类型字段确定的。Netlink 定义了如下标准消息类型:

  • NLMSG_NOOP - 无需任何操作,消息必须被丢弃
  • NLMSG_ERROR - 错误消息或者是 ACK,
  • NLMSG_DONE - 分段序列的结束
  • NLMSG_OVERRUN - 通知消息越界错误

  每个 netlink 协议都可以自由的定义自己的消息类型。需要注意的是小于 NLMSG_MIN_TYPE(0x10) 的类型是保留的,所以不能使用。通常我们会定义自己的消息类型来实现 RPC 模式。假设你的 netlink 协议的目的是允许你 配置一个网络设备的某些部分,所以你想要提供各种配置选项的读/写访问。完成这项任务 典型的 “netlik 解决方案” 是定义两种消息类型MSG_SETCFG,MSG_GETCFG:

#define MSG_SETCFG    0x11
#define MSG_GETCFG    0x12

  发送一条 MSG_GETCFG 请求消息通常会收到一条包含当前配置信息的类型为 MSG_SETCFG 的应答消息。用面向对象的术语来说这叫做“内核在用户空间设置了配置信息的本地拷贝”


配置信息可以通过发送一条 MSG_SETCFG 信息来更改,这条消息会收到一条 ACK响应信息 或是一条错误信息。

  此外,内核也可以在配置信息发生改变的时候发送通知信息,这样用户空间应用程序就可以 使用监听而不是频繁轮询的方式来获取改变信息。通知消息通常是使用目前已有的消息类型 这就需要应用程序使用不同的套接字处理请求消息和通知消息,当然你也可以使用特殊的消息类型来单独表示通知信息。

分片消息

  理论上一条 netlink 消息的最大长度是 4GiB,但是套接字的缓冲区一般不会设置有如此大的空间来容纳4GiB消息。通常情况下,消息的长度被限制在页的大小(PAGE_SIZE )之内,然后使用分片机制把大消息分割为多个消息。分片消息设有NLM_F_MULTI标志位,接收者需要不断的接收和解析消息,直至收到一个消息类型为NLMSG_DONE的消息为止。
  和分片之后的ip包不一样,分片之后的Netlink消息无需重组,但是如果协议需要重组,也可以执行重组动作。分片消息经常会被用来发送对象列表或者是对象树,这种情况下消息段只是简单的承载几个对象,一般允许单独处理每个消息分片。

分片消息

错误消息

  错误消息可以作为请求消息的响应发送回去,错误消息必须使用标准的消息类型 NLMSG_ERROR,它的有效载荷是由错误码和原来的请求消息头部组成。

错误消息

注意:错误消息的序列号必须和导致错误发生的请求消息的序列号设置为一致。

ACKs消息

  发送方可以通过设置NLM_F_ACK标志位来要求接收方为处理过的每一个请求消息都发送一 个ACK消息。这种方式通常是用来让发送方在请求被接收方处理之后同步下一步的操作。

ACKs消息

  ACK 消息和错误消息使用一样的消息类型(NLMSG_ERROR)和负荷格式,不同的是 ACK 消息 的错误代码被设置为 0。

消息标志

#define NLM_F_REQUEST           1
#define NLM_F_MULTI             2
#define NLM_F_ACK               4
#define NLM_F_ECHO              8
  • NLM_F_REQUEST - 请求消息
  • NLM_F_MULTI - 分片消息
  • NLM_F_ACK - 请求了 ACK 回复
  • NLM_F_ECHO - 请求回应这个请求消息。

  NLM_F_ECHO标志和NLM_F_ACK标志类似,它可以和NLM_F_REQUEST标志位一起使 用,使得发送者能够收到作为这条请求消息的响应而产生的通知信息,无论发送者是否订阅过相应的多播组。
GET 请求还定义了一些额外的通用标志位:

#define NLM_F_ROOT      0x100
#define NLM_F_MATCH     0x200
#define NLM_F_ATOMIC    0x400
#define NLM_F_DUMP      (NLM_F_ROOT|NLM_F_MATCH)
  • NLM_F_ROOT - 返回树的根节点。
  • NLM_F_MATCH - 返回所有匹配的节点。
  • NLM_F_ATOMIC - 已废弃,以前用来请求一个原子操作
  • NLM_F_DUMP - 返回一个含有所有对象的列表(NLM_F_ROOT|NLM_F_MATCH)

  这些标志的使用是完全可选的,许多netlink协议都只使用NLM_F_DUMP标志。这个标志通常用来请求接收者发送一个包含所有对象的列表,而这个列表则通常是一系列的消息分片。
  还有一些和 NEW 或者是 SET 请求相关的标志。这些标志和 GET 的那些标志是彼此互斥的 :

#define NLM_F_REPLACE   0x100
#define NLM_F_EXCL      0x200
#define NLM_F_CREATE    0x400
#define NLM_F_APPEND    0x800
  • NLM_F_REPLACE - 如果对象存在的话,替换它。
  • NLM_F_EXCL - 如果这个对象存在的话,就不用更新它。
  • NLM_F_CREATE - 如果对象不存在的话,创建它。
  • NLM_F_APPEND - 在对象列表的末尾添加新的对象。

这些标志含义在不同的 netlink 协议中可能会有细微的差别。

序列号

  Netlink允许通过序列号来关联回复和请求。需要注意的是,这里的序列号和 TCP 这类的协议的序列号是不一样的,Netlink的序列号并不强制使用。序列号唯一的用途就是把一条应答消息和相应的请求消息联系起来,序列号是以单个套接字为基础来管理。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,639评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,277评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,221评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,474评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,570评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,816评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,957评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,718评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,176评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,511评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,646评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,322评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,934评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,755评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,987评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,358评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,514评论 2 348

推荐阅读更多精彩内容

  • 操作系统概论 操作系统的概念 操作系统是指控制和管理计算机的软硬件资源,并合理的组织调度计算机的工作和资源的分配,...
    野狗子嗷嗷嗷阅读 11,905评论 3 34
  • 计算机系统漫游 代码从文本到可执行文件的过程(c语言示例):预处理阶段,处理 #inlcude , #defin...
    willdimagine阅读 3,571评论 0 5
  • 多线程、特别是NSOperation 和 GCD 的内部原理。运行时机制的原理和运用场景。SDWebImage的原...
    LZM轮回阅读 2,004评论 0 12
  • 谁的故事:木月晴图片来源:百度 月晴早上开始给小蝴蝶挑选结婚礼物,挑来挑去都没有称心如意的,十字绣?加湿器?蓝牙音...
    笑六子阅读 177评论 0 0
  • 沙漠的日落快极了,这片广袤的黄色土地很快披上一层深色薄纱。只有沙丘的最顶端,还能依稀看得到一点点光亮,剩下...
    張小兵阅读 593评论 0 6