Netlink 库 -- 官方开发者教程中文版第一部分

1. 引言

核心库(core library)提供了使用 netlink 套接字进行通信的基础功能。它处理套接 字的连接建立和断开、发送和接收数据、构造和解析消息、提供可配置的接收状态机。除此 之外它还提供了一套抽象数据类型的框架,这套框架使得基于对象的 netlink 协议实现 起来更加的简单,在这种协议中,对象可以通过基于 netlink 的协议来添加、删除、 或者修改。

库的层次结构

这工程被分割成了下面几个库:

结构层次图

Netlink Library(libnl)

套接字的处理、发送和接收数据、消息的构造和解析、……

Routing Family Library(libnl-route)

地址、链路、邻居节点、路由、流量控制、邻居节点表、……

Netfilter Library(libnl-nf)

连接追踪、记录日志、排队(queueing)

Generice Netlink Library(libnl-genl)

控制器的 API,协议簇(family)和命令的注册

1.1. 如何阅读这份文档

这些库提供了大量的 API,通常大部分的应用程序都只需要用到其中的一小部分。有些用户 可能只会关心低层(low level)的 netlink 消息处理 API,而其他用户可能主要使用高层 (high level)的 API,这些主要依赖于你的应用程序的类型。

无论你是属于那种情况,我们都推荐你首先熟悉下 netlink 协议。

低层 API 在下面两部分中有详细介绍:

使用 autoconf 检查库是否存在

那些使用 autoconf 的项目可以使用 PKG_CHECK_MODULES() 来检测系统中是否存在某个特定 版本的 libnl。下面这个例子同时也展示了如何取得链接到 libnl 库所需要的 CFLAGS 和 链接依赖。

下面这个例子展示 了如何检查特定版本的 libnl 是否存在。如果存在,这个例子也展示了 如何正确的扩展 CFLAGS 和 LIBS 变量:

1
2
3
4
5
PKG_CHECK_MODULES(LIBNL3,libnl3-3.0>=3.1,[have_libnl3]=yes,[have_libnl3=no])
if (test "$(have_libnl3)"="yes"); then
CFLAGS+="$(LIBNL3_CFLAGS)"
LIBS+="$(LIBNL3_LIBS)"
fi

注意: pkgconfig 被命名成 libnl-3.0.pc 是遗留问题,它实际上也包含了版本号大于 3.1 的库。

头文件

需要包含的头文件主要是 <netlink/netlink.h> 这个文件。根据你使用的子系统和组件的 不同,你可能还需要在你头文件中添加一些额外的头文件。

1
2
3
#include <netlink/netlinl.h>
#include <netlink/cache.h>
#include <netlink/route/link.h>

依赖于版本号的代码

如果你希望能在你的代码中链接 libnl 的多个版本,你可以让编译器根据你想要链接的 libnl 库的特定版本来编译你代码中包含的特定部分的代码。

1
2
3
4
5
#include <netlink/version.h>

#if LIBNL_VER_NUM >= LIBNL_VER(3.1)
/* include code if compiled with libnl version >= 3.1 */
#end if

链接

1
$gcc myprogram.c -o myprogram $(pkgconfig --cflags --libs libnl-3.0)

1.3. 调试

这个库在编译的时候包含了调试语句,这使得它可以在你把 NLDBG 这个环境变量的值设置为

0 的值的时候往 stderr 中打印调试信息。

1
$ NLDBG=2 ./myprogram
表 1. 调试级别
级别 描述

0

关闭调试 (默认)

1

警告信息、重要的事件和通知信息

2

多一些更不重要的信息

3

导致调试信息刷屏重复性事件

4

比上面的信息还更不重要的消息

Netlink 协议的调试

通常查看套接字之间交换的 netlink 消息流是非常有用的。把环境变量 NLCB 的值设置为 debug(NLCB=debug)可以运行调试消息处理器,它会把交换的 netlink 消息打印成易于 我们阅读的格式并输出到 stderr 上。

$ NLCB=debug ./myprogram
-- Debug: Sent Message:
--------------------------   BEGIN NETLINK MESSAGE ---------------------------
  [HEADER] 16 octets
    .nlmsg_len = 20
    .nlmsg_type = 18 &lt;route/link::get&gt;
    .nlmsg_flags = 773 &lt;REQUEST,ACK,ROOT,MATCH&gt;
    .nlmsg_seq = 1301410712
    .nlmsg_pid = 20014
  [PAYLOAD] 16 octets
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00       ................
---------------------------  END NETLINK MESSAGE   ---------------------------
-- Debug: Received Message:
--------------------------   BEGIN NETLINK MESSAGE ---------------------------
  [HEADER] 16 octets
    .nlmsg_len = 996
    .nlmsg_type = 16 &lt;route/link::new&gt;
    .nlmsg_flags = 2 &lt;MULTI&gt;
    .nlmsg_seq = 1301410712
    .nlmsg_pid = 20014
  [PAYLOAD] 16 octets
    00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00       ........I.......
  [ATTR 03] 3 octets
    6c 6f 00                                              lo.
  [PADDING] 1 octets
    00                                                    .
  [ATTR 13] 4 octets
    00 00 00 00                                           ....
  [ATTR 16] 1 octets
    00                                                    .
  [PADDING] 3 octets
    00 00 00                                              ...
  [ATTR 17] 1 octets
    00                                                    .
  [...]
---------------------------  END NETLINK MESSAGE   ---------------------------