vimer linux kernel 爱好者

netlink嵌套字

2017-05-03

redhat

如果你有用户空间的程序去测试,请参考这篇文章1

在net/下,有af_netlink.c af_netlink.h genetlink.c和diag.c

af_netlink 文件中提供了绝大多数的API,genetlink提供了新的API,这使得更容易创建netlink消息。diag.c是为了dump netlink消息,里面是相关的API。

netlink较其他内核与用户空间的交流方式具有以下优势:

不需要poll模式,前文我们说了。一个用户空间的程序打开一个socket,然后直接recvmsg(),如果没有从内核发送过来信息,就进入一个阻塞状态。例如,iproute2包中/lib/libnetlink.c中的 rtnl_listen()方法。还有一个优势是可以允许内核发送异步消息到用户空间,这不需要用户空间的程序去特定的抓取。最后一个优势就是netlink支持多播传输机制。

同样,创建netlink嵌套字使用socket()方法,类型可以是SOCK_RAW或者SOCK_DGRAM.

netlink嵌套字既可以在用户空间创建,也可以在内核空间创建。内核里使用方法netlink_kernel_create()去创建,这两者都会产生一个netlink_sock对象。用户空间的会被netlink_create()方法处理。内核里是__netlink_kernel_create(),这个方法设置了NETLINK_KERNEL_SOCKET_标志。最终所有的方法会调用__netlink_create()(源头其实是sk_alloc()),

用户空间的程序:

socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

然后创造一个sockaddr_nl的对象实例

使用netlink sockets 库

libnl是与内核空间交流的用户空间程序的API,iproute2就是使用的libnl库,一般在这个源代码包的下面,有基本核心库(libnl),它支持一般netlink家族(libnl-genl),路由家族(libnl-route)和netfilter家族(libnl-nf).还有一个最小化的用户空间的库函数叫libmnl.

相关的源代码在这里here,下面就是结构图:

进行开发的文档在这里

2018-05-21-netlink_user.png

先来一段用户空间的程序,看看大体概貌

#include <netlink/netlink.h>
#include <errno.h>

int main(int argc, char *argv[])
{
	struct nl_sock *h[1025];
	int i;

	h[0] = nl_socket_alloc();
	printf("Created handle with port 0x%x\n",
			nl_socket_get_local_port(h[0]));
	nl_socket_free(h[0]);
	h[0] = nl_socket_alloc();
	printf("Created handle with port 0x%x\n",
			nl_socket_get_local_port(h[0]));
	nl_socket_free(h[0]);

	for (i = 0; i < 1025; i++) {
		h[i] = nl_socket_alloc();
		if (h[i] == NULL)
			nl_perror(ENOMEM, "Unable to allocate socket");
		else
			printf("Created handle with port 0x%x\n",
				nl_socket_get_local_port(h[i]));
	}

	return 0;
}

这是在编译的时候,有些麻烦,

gcc program.c $(pkg-config --cflags --libs libnl-3.0)

这里涉及了pkg-config的用法。这个工具还是非常有用的,他解决了有关已安装的库函数中的种种使用的问题。比如,库函数的版本、链接位置…pkg-config的具体以后补充。

Message Format

2018-05-21-nlmsghdr.png

struct nlmsghdr{
	__u32 nlmsg_len;
	__u32 nlmsg_type;
	__u32 nlmsg_flags;
	__u32 nlmsg_seq;
	__u32 nlmsg_pid;
}

from <linux/uapi/linux/netlink.h>.这里重点介绍几个。

nlmsg_len is the length of the message including the header

nlmsg_type four basic netlink message header types:

NLMSG_NOOP : no operations, message must be discarded
NLMSG_ERROR: Error occured
NLMSG_DONE: A multipart message is terminated
NLMSG_OVERRUN: error, data was lost

nlmsg_flags:

NLM_F_REQUEST - Message is a request, see Message Types.

NLM_F_MULTI - Multipart message, see Multipart Messages

NLM_F_ACK - ACK message requested, see ACKs.

NLM_F_ECHO - Request to echo the request.

NLM_F_ROOT - Return based on root of tree.

NLM_F_MATCH - Return all matching entries.

NLM_F_ATOMIC - Obsoleted, once used to request an atomic operation.

NLM_F_DUMP - Return a list of all objects (NLM_F_ROOT|NLM_F_MATCH).

NLM_F_REPLACE - Replace an existing object if it exists.

NLM_F_EXCL - Do not update object if it exists already.

NLM_F_CREATE - Create object if it does not exist yet.

NLM_F_APPEND - Add object at end of list.

nlmsg_seq: the message sequence number

nlmsg_pid: is the sending port id

看一下sockaddr_nl的结构体


struct sockaddr_nl {
	__kernel_sa_family_t	nl_family;	/* AF_NETLINK	*/
	unsigned short	nl_pad;		/* zero		*/
	__u32		nl_pid;		/* port ID	*/
       	__u32		nl_groups;	/* multicast groups mask */
};

上面的成员参数可以看注释,这里说一下nl_pid,它是netlink socket的单播地址,对于内核来说,它应该是0;对于用户空间来说,应该是运行它的的pid(使用getpid()).

socket monitoring interface

sock_diag就是提供了基于netlink子系统、可以得到有关socket的信息。有关网络的工具ss就是大量使用了sock_diag.


下一篇 icmp分析

Comments

Content